rnd-19990108-1
[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   for(x=0; x<ED_FIELDX; x++)
1374     for(y=0; y<ED_FIELDY; y++)
1375       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1376
1377   redraw_mask |= REDRAW_FIELD;
1378 }
1379
1380 void DrawMicroLevel(int xpos, int ypos)
1381 {
1382   int x,y;
1383
1384   /* determine border element for this level */
1385   SetBorderElement();
1386
1387   XFillRectangle(display, drawto, gc,
1388                  xpos - MICRO_TILEX, ypos - MICRO_TILEY,
1389                  MICRO_TILEX * (STD_LEV_FIELDX + 2),
1390                  MICRO_TILEY * (STD_LEV_FIELDY + 2));
1391   if (lev_fieldx < STD_LEV_FIELDX)
1392     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1393   if (lev_fieldy < STD_LEV_FIELDY)
1394     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1395
1396   for(x=-1; x<=STD_LEV_FIELDX; x++)
1397     for(y=-1; y<=STD_LEV_FIELDY; y++)
1398       if (x >= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy)
1399         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1400                          Ur[x][y]);
1401       else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1)
1402         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1403                          BorderElement);
1404
1405   XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1406
1407   if (level.name)
1408   {
1409     int len = strlen(level.name);
1410     int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1411     int lypos = MICROLABEL_YPOS;
1412
1413     DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1414   }
1415
1416   redraw_mask |= REDRAW_MICROLEV;
1417 }
1418
1419 int REQ_in_range(int x, int y)
1420 {
1421   if (y > DY+249 && y < DY+278)
1422   {
1423     if (x > DX+1 && x < DX+48)
1424       return 1;
1425     else if (x > DX+51 && x < DX+98) 
1426       return 2;
1427   }
1428   return 0;
1429 }
1430
1431 boolean Request(char *text, unsigned int req_state)
1432 {
1433   int mx, my, ty, result = -1;
1434   unsigned int old_door_state;
1435
1436 #ifndef MSDOS
1437   /* pause network game while waiting for request to answer */
1438   if (options.network &&
1439       game_status == PLAYING &&
1440       req_state & REQUEST_WAIT_FOR)
1441     SendToServer_PausePlaying();
1442 #endif
1443
1444   old_door_state = GetDoorState();
1445
1446   CloseDoor(DOOR_CLOSE_1);
1447
1448   /* Alten Türinhalt sichern */
1449   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1450             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1451             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1452
1453   /* Fragetext schreiben */
1454   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1455                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1456
1457   for(ty=0; ty<13; ty++)
1458   {
1459     int tx, tl, tc;
1460     char txt[256];
1461
1462     if (!*text)
1463       break;
1464
1465     for(tl=0,tx=0; tx<7; tl++,tx++)
1466     {
1467       tc = *(text + tx);
1468       if (!tc || tc == 32)
1469         break;
1470     }
1471     if (!tl)
1472     { 
1473       text++; 
1474       ty--; 
1475       continue; 
1476     }
1477     sprintf(txt, text); 
1478     txt[tl] = 0;
1479     DrawTextExt(pix[PIX_DB_DOOR], gc,
1480                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1481                 txt, FS_SMALL, FC_YELLOW);
1482     text += tl + (tc == 32 ? 1 : 0);
1483   }
1484
1485   if (req_state & REQ_ASK)
1486   {
1487     DrawYesNoButton(BUTTON_OK, DB_INIT);
1488     DrawYesNoButton(BUTTON_NO, DB_INIT);
1489   }
1490   else if (req_state & REQ_CONFIRM)
1491   {
1492     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1493   }
1494   else if (req_state & REQ_PLAYER)
1495   {
1496     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1497     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1498     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1499     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1500   }
1501
1502   OpenDoor(DOOR_OPEN_1);
1503   ClearEventQueue();
1504
1505   if (!(req_state & REQUEST_WAIT_FOR))
1506     return(FALSE);
1507
1508   if (game_status != MAINMENU)
1509     InitAnimation();
1510
1511   button_status = MB_RELEASED;
1512
1513   while(result < 0)
1514   {
1515     if (XPending(display))
1516     {
1517       XEvent event;
1518
1519       XNextEvent(display, &event);
1520
1521       switch(event.type)
1522       {
1523         case ButtonPress:
1524         case ButtonRelease:
1525         case MotionNotify:
1526         {
1527           int choice;
1528
1529           if (event.type == MotionNotify)
1530           {
1531             motion_status = TRUE;
1532             mx = ((XMotionEvent *) &event)->x;
1533             my = ((XMotionEvent *) &event)->y;
1534           }
1535           else
1536           {
1537             motion_status = FALSE;
1538             mx = ((XButtonEvent *) &event)->x;
1539             my = ((XButtonEvent *) &event)->y;
1540             if (event.type==ButtonPress)
1541               button_status = ((XButtonEvent *) &event)->button;
1542             else
1543               button_status = MB_RELEASED;
1544           }
1545
1546           if (req_state & REQ_ASK)
1547             choice = CheckYesNoButtons(mx,my,button_status);
1548           else if (req_state & REQ_CONFIRM)
1549             choice = CheckConfirmButton(mx,my,button_status);
1550           else
1551             choice = CheckPlayerButtons(mx,my,button_status);
1552
1553           switch(choice)
1554           {
1555             case BUTTON_OK:
1556               result = TRUE;
1557               break;
1558             case BUTTON_NO:
1559               result = FALSE;
1560               break;
1561             case BUTTON_CONFIRM:
1562               result = TRUE | FALSE;
1563               break;
1564
1565             case BUTTON_PLAYER_1:
1566               result = 1;
1567               break;
1568             case BUTTON_PLAYER_2:
1569               result = 2;
1570               break;
1571             case BUTTON_PLAYER_3:
1572               result = 3;
1573               break;
1574             case BUTTON_PLAYER_4:
1575               result = 4;
1576               break;
1577
1578             default:
1579               break;
1580           }
1581           break;
1582         }
1583
1584         case KeyPress:
1585           switch(XLookupKeysym((XKeyEvent *)&event,
1586                                ((XKeyEvent *)&event)->state))
1587           {
1588             case XK_Return:
1589               result = 1;
1590               break;
1591
1592             case XK_Escape:
1593               result = 0;
1594               break;
1595
1596             default:
1597               break;
1598           }
1599           if (req_state & REQ_PLAYER)
1600             result = 0;
1601           break;
1602
1603         case KeyRelease:
1604           key_joystick_mapping = 0;
1605           break;
1606
1607         default:
1608           HandleOtherEvents(&event);
1609           break;
1610       }
1611     }
1612     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1613     {
1614       int joy = AnyJoystick();
1615
1616       if (joy & JOY_BUTTON_1)
1617         result = 1;
1618       else if (joy & JOY_BUTTON_2)
1619         result = 0;
1620     }
1621
1622     DoAnimation();
1623
1624     /* don't eat all CPU time */
1625     Delay(10);
1626   }
1627
1628   if (game_status != MAINMENU)
1629     StopAnimation();
1630
1631   if (!(req_state & REQ_STAY_OPEN))
1632   {
1633     CloseDoor(DOOR_CLOSE_1);
1634
1635     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1636     {
1637       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1638                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1639                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1640       OpenDoor(DOOR_OPEN_1);
1641     }
1642   }
1643
1644 #ifndef MSDOS
1645   /* continue network game after request */
1646   if (options.network &&
1647       game_status == PLAYING &&
1648       req_state & REQUEST_WAIT_FOR)
1649     SendToServer_ContinuePlaying();
1650 #endif
1651
1652   return(result);
1653 }
1654
1655 unsigned int OpenDoor(unsigned int door_state)
1656 {
1657   unsigned int new_door_state;
1658
1659   if (door_state & DOOR_COPY_BACK)
1660   {
1661     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1662               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1663               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1664     door_state &= ~DOOR_COPY_BACK;
1665   }
1666
1667   new_door_state = MoveDoor(door_state);
1668
1669   return(new_door_state);
1670 }
1671
1672 unsigned int CloseDoor(unsigned int door_state)
1673 {
1674   unsigned int new_door_state;
1675
1676   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1677             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1678   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1679             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1680
1681   new_door_state = MoveDoor(door_state);
1682
1683   return(new_door_state);
1684 }
1685
1686 unsigned int GetDoorState()
1687 {
1688   return(MoveDoor(DOOR_GET_STATE));
1689 }
1690
1691 unsigned int MoveDoor(unsigned int door_state)
1692 {
1693   static int door1 = DOOR_OPEN_1;
1694   static int door2 = DOOR_CLOSE_2;
1695   static unsigned long door_delay = 0;
1696   int x, start, stepsize = 2;
1697   unsigned long door_delay_value = stepsize * 5;
1698
1699   if (door_state == DOOR_GET_STATE)
1700     return(door1 | door2);
1701
1702   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1703     door_state &= ~DOOR_OPEN_1;
1704   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1705     door_state &= ~DOOR_CLOSE_1;
1706   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1707     door_state &= ~DOOR_OPEN_2;
1708   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1709     door_state &= ~DOOR_CLOSE_2;
1710
1711   if (setup.quick_doors)
1712   {
1713     stepsize = 20;
1714     door_delay_value = 0;
1715     StopSound(SND_OEFFNEN);
1716   }
1717
1718   if (door_state & DOOR_ACTION)
1719   {
1720     if (!(door_state & DOOR_NO_DELAY))
1721       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1722
1723     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1724
1725     for(x=start; x<=DXSIZE; x+=stepsize)
1726     {
1727       WaitUntilDelayReached(&door_delay, door_delay_value);
1728
1729       if (door_state & DOOR_ACTION_1)
1730       {
1731         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1732         int j = (DXSIZE - i) / 3;
1733
1734         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1735                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1736                   DXSIZE,DYSIZE - i/2, DX, DY);
1737
1738         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1739
1740         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1741                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1742         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1743                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1744         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1745                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1746                   DY + 140 + j);
1747         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1748                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1749         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1750                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1751         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1752                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1753
1754         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1755                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1756                   DX, DY + 77 - j);
1757         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1758                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1759                   DX, DY + 203 - j);
1760         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1761                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1762         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1763                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1764                   DX + DXSIZE - i, DY + 77 + j);
1765         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1766                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1767                   DX + DXSIZE - i, DY + 203 + j);
1768
1769         redraw_mask |= REDRAW_DOOR_1;
1770       }
1771
1772       if (door_state & DOOR_ACTION_2)
1773       {
1774         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1775         int j = (VXSIZE - i) / 3;
1776
1777         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1778                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1779                   VXSIZE, VYSIZE - i/2, VX, VY);
1780
1781         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1782
1783         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1784                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1785         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1786                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1787         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1788                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1789         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1790                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1791
1792         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1793                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1794                   VX, VY + VYSIZE / 2 - j);
1795         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1796                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1797         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1798                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1799                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1800
1801         redraw_mask |= REDRAW_DOOR_2;
1802       }
1803
1804       BackToFront();
1805
1806       if (game_status == MAINMENU)
1807         DoAnimation();
1808     }
1809   }
1810
1811   if (setup.quick_doors)
1812     StopSound(SND_OEFFNEN);
1813
1814   if (door_state & DOOR_ACTION_1)
1815     door1 = door_state & DOOR_ACTION_1;
1816   if (door_state & DOOR_ACTION_2)
1817     door2 = door_state & DOOR_ACTION_2;
1818
1819   return(door1 | door2);
1820 }
1821
1822 int ReadPixel(Drawable d, int x, int y)
1823 {
1824   XImage *pixel_image;
1825   unsigned long pixel_value;
1826
1827   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1828   pixel_value = XGetPixel(pixel_image, 0, 0);
1829
1830   XDestroyImage(pixel_image);
1831
1832   return pixel_value;
1833 }
1834
1835 int el2gfx(int element)
1836 {
1837   switch(element)
1838   {
1839     case EL_LEERRAUM:           return -1;
1840     case EL_ERDREICH:           return GFX_ERDREICH;
1841     case EL_MAUERWERK:          return GFX_MAUERWERK;
1842     case EL_FELSBODEN:          return GFX_FELSBODEN;
1843     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1844     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1845     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1846     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1847     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1848     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1849     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1850     case EL_SPIELER1:           return GFX_SPIELER1;
1851     case EL_SPIELER2:           return GFX_SPIELER2;
1852     case EL_SPIELER3:           return GFX_SPIELER3;
1853     case EL_SPIELER4:           return GFX_SPIELER4;
1854     case EL_KAEFER:             return GFX_KAEFER;
1855     case EL_KAEFER_R:           return GFX_KAEFER_R;
1856     case EL_KAEFER_O:           return GFX_KAEFER_O;
1857     case EL_KAEFER_L:           return GFX_KAEFER_L;
1858     case EL_KAEFER_U:           return GFX_KAEFER_U;
1859     case EL_FLIEGER:            return GFX_FLIEGER;
1860     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1861     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1862     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1863     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1864     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1865     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1866     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1867     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1868     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1869     case EL_FIREFLY:            return GFX_FIREFLY;
1870     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1871     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1872     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1873     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1874     case EL_MAMPFER:            return GFX_MAMPFER;
1875     case EL_ROBOT:              return GFX_ROBOT;
1876     case EL_BETON:              return GFX_BETON;
1877     case EL_DIAMANT:            return GFX_DIAMANT;
1878     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1879     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1880     case EL_TROPFEN:            return GFX_TROPFEN;
1881     case EL_BOMBE:              return GFX_BOMBE;
1882     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
1883     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1884     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1885     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1886     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1887     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1888     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1889     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1890     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1891     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1892     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1893     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1894     case EL_LIFE:               return GFX_LIFE;
1895     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1896     case EL_DYNAMIT:            return GFX_DYNAMIT;
1897     case EL_BADEWANNE:          return GFX_BADEWANNE;
1898     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1899     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1900     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
1901     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
1902     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
1903     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
1904     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
1905     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
1906     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
1907     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
1908     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
1909     case EL_PFORTE1:            return GFX_PFORTE1;
1910     case EL_PFORTE2:            return GFX_PFORTE2;
1911     case EL_PFORTE3:            return GFX_PFORTE3;
1912     case EL_PFORTE4:            return GFX_PFORTE4;
1913     case EL_PFORTE1X:           return GFX_PFORTE1X;
1914     case EL_PFORTE2X:           return GFX_PFORTE2X;
1915     case EL_PFORTE3X:           return GFX_PFORTE3X;
1916     case EL_PFORTE4X:           return GFX_PFORTE4X;
1917     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
1918     case EL_PACMAN:             return GFX_PACMAN;
1919     case EL_PACMAN_R:           return GFX_PACMAN_R;
1920     case EL_PACMAN_O:           return GFX_PACMAN_O;
1921     case EL_PACMAN_L:           return GFX_PACMAN_L;
1922     case EL_PACMAN_U:           return GFX_PACMAN_U;
1923     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
1924     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
1925     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
1926     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
1927     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
1928     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
1929     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
1930     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
1931     case EL_MAUER_X:            return GFX_MAUER_X;
1932     case EL_MAUER_Y:            return GFX_MAUER_Y;
1933     case EL_MAUER_XY:           return GFX_MAUER_XY;
1934     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
1935     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
1936     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
1937     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
1938     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
1939     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
1940     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
1941     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
1942     case EL_MAMPFER2:           return GFX_MAMPFER2;
1943     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
1944     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
1945     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
1946     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
1947     case EL_DYNABOMB:           return GFX_DYNABOMB;
1948     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
1949     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
1950     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
1951     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
1952     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
1953     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
1954     case EL_MAULWURF:           return GFX_MAULWURF;
1955     case EL_PINGUIN:            return GFX_PINGUIN;
1956     case EL_SCHWEIN:            return GFX_SCHWEIN;
1957     case EL_DRACHE:             return GFX_DRACHE;
1958     case EL_SONDE:              return GFX_SONDE;
1959     case EL_PFEIL_L:            return GFX_PFEIL_L;
1960     case EL_PFEIL_R:            return GFX_PFEIL_R;
1961     case EL_PFEIL_O:            return GFX_PFEIL_O;
1962     case EL_PFEIL_U:            return GFX_PFEIL_U;
1963     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
1964     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
1965     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
1966
1967     default:
1968     {
1969       if (IS_CHAR(element))
1970         return GFX_CHAR_START + (element - EL_CHAR_START);
1971       else if (element >= EL_SP_START && element <= EL_SP_END)
1972       {
1973         int nr_element = element - EL_SP_START;
1974         int gfx_per_line = 8;
1975         int nr_graphic =
1976           (nr_element / gfx_per_line) * MORE_PER_LINE +
1977           (nr_element % gfx_per_line);
1978
1979         return GFX_START_ROCKSMORE + nr_graphic;
1980       }
1981       else
1982         return -1;
1983     }
1984   }
1985 }