rnd-19981230-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     DrawGraphicThruMask(sx, sy, graphic + phase);
547   }
548
549   if ((last_jx != jx || last_jy != jy) &&
550       Feld[last_jx][last_jy] == EL_EXPLODING)
551   {
552     int phase = Frame[last_jx][last_jy];
553     int delay = 2;
554
555     if (phase > 2)
556       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
557                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
558   }
559
560   if (setup.direct_draw)
561   {
562     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
563     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
564     int x_size = TILEX * (1 + ABS(jx - last_jx));
565     int y_size = TILEY * (1 + ABS(jy - last_jy));
566
567     XCopyArea(display, drawto_field, window, gc,
568               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
569     SetDrawtoField(DRAW_DIRECT);
570   }
571
572   MarkTileDirty(sx,sy);
573 }
574
575 static int getGraphicAnimationPhase(int frames, int delay, int mode)
576 {
577   int phase;
578
579   if (mode == ANIM_OSCILLATE)
580   {
581     int max_anim_frames = 2 * frames - 2;
582     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
583     phase = (phase < frames ? phase : max_anim_frames - phase);
584   }
585   else
586     phase = (FrameCounter % (delay * frames)) / delay;
587
588   if (mode == ANIM_REVERSE)
589     phase = -phase;
590
591   return(phase);
592 }
593
594 void DrawGraphicAnimationExt(int x, int y, int graphic,
595                              int frames, int delay, int mode, int mask_mode)
596 {
597   int phase = getGraphicAnimationPhase(frames, delay, mode);
598
599   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
600   {
601     if (mask_mode == USE_MASKING)
602       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
603     else
604       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
605   }
606 }
607
608 void DrawGraphicAnimation(int x, int y, int graphic,
609                           int frames, int delay, int mode)
610 {
611   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
612 }
613
614 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
615                                   int frames, int delay, int mode)
616 {
617   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
618 }
619
620 void DrawGraphic(int x, int y, int graphic)
621 {
622 #if DEBUG
623   if (!IN_SCR_FIELD(x,y))
624   {
625     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
626     printf("DrawGraphic(): This should never happen!\n");
627     return;
628   }
629 #endif
630
631   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
632   MarkTileDirty(x,y);
633 }
634
635 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
636 {
637   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
638   {
639     graphic -= GFX_START_ROCKSSCREEN;
640     XCopyArea(display, pix[PIX_BACK], d, gc,
641               SX + (graphic % GFX_PER_LINE) * TILEX,
642               SY + (graphic / GFX_PER_LINE) * TILEY,
643               TILEX, TILEY, x, y);
644   }
645   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
646   {
647     graphic -= GFX_START_ROCKSMORE;
648     XCopyArea(display, pix[PIX_MORE], d, gc,
649               (graphic % MORE_PER_LINE) * TILEX,
650               (graphic / MORE_PER_LINE) * TILEY,
651               TILEX, TILEY, x, y);
652   }
653   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
654   {
655     graphic -= GFX_START_ROCKSHEROES;
656     XCopyArea(display, pix[PIX_HEROES], d, gc,
657               (graphic % HEROES_PER_LINE) * TILEX,
658               (graphic / HEROES_PER_LINE) * TILEY,
659               TILEX, TILEY, x, y);
660   }
661   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
662   {
663     graphic -= GFX_START_ROCKSFONT;
664     XCopyArea(display, pix[PIX_BIGFONT], d, gc,
665               (graphic % FONT_CHARS_PER_LINE) * TILEX,
666               (graphic / FONT_CHARS_PER_LINE) * TILEY +
667               FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY,
668               TILEX, TILEY, x, y);
669   }
670   else
671     XFillRectangle(display, d, gc, x, y, TILEX, TILEY);
672 }
673
674 void DrawGraphicThruMask(int x, int y, int graphic)
675 {
676 #if DEBUG
677   if (!IN_SCR_FIELD(x,y))
678   {
679     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
680     printf("DrawGraphicThruMask(): This should never happen!\n");
681     return;
682   }
683 #endif
684
685   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
686   MarkTileDirty(x,y);
687 }
688
689 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
690 {
691   int src_x, src_y;
692   int tile = graphic;
693   Pixmap src_pixmap;
694   GC drawing_gc;
695
696   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
697   {
698     src_pixmap = pix[PIX_BACK];
699     drawing_gc = clip_gc[PIX_BACK];
700     graphic -= GFX_START_ROCKSSCREEN;
701     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX;
702     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY;
703   }
704   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
705   {
706     src_pixmap = pix[PIX_MORE];
707     drawing_gc = clip_gc[PIX_MORE];
708     graphic -= GFX_START_ROCKSMORE;
709     src_x  = (graphic % MORE_PER_LINE) * TILEX;
710     src_y  = (graphic / MORE_PER_LINE) * TILEY;
711   }
712   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
713   {
714     src_pixmap = pix[PIX_HEROES];
715     drawing_gc = clip_gc[PIX_HEROES];
716     graphic -= GFX_START_ROCKSHEROES;
717     src_x  = (graphic % HEROES_PER_LINE) * TILEX;
718     src_y  = (graphic / HEROES_PER_LINE) * TILEY;
719   }
720   else
721   {
722     DrawGraphicExt(d, gc, dest_x,dest_y, graphic);
723     return;
724   }
725
726   if (tile_clipmask[tile] != None)
727   {
728     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
729     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
730     XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
731               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
732   }
733   else
734   {
735 #if DEBUG
736     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
737 #endif
738
739     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
740     XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
741               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
742   }
743 }
744
745 void DrawMiniGraphic(int x, int y, int graphic)
746 {
747   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
748   MarkTileDirty(x/2, y/2);
749 }
750
751 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
752 {
753   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
754   {
755     graphic -= GFX_START_ROCKSSCREEN;
756     XCopyArea(display, pix[PIX_BACK], d, gc,
757               MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX,
758               MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY,
759               MINI_TILEX, MINI_TILEY, x, y);
760   }
761   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
762   {
763     graphic -= GFX_START_ROCKSMORE;
764     XCopyArea(display, pix[PIX_MORE], d, gc,
765               MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX,
766               MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY,
767               MINI_TILEX, MINI_TILEY, x, y);
768   }
769   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
770   {
771     graphic -= GFX_START_ROCKSFONT;
772     XCopyArea(display, pix[PIX_SMALLFONT], d, gc,
773               (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE,
774               (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
775               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT,
776               MINI_TILEX, MINI_TILEY, x, y);
777   }
778   else
779     XFillRectangle(display, d, gc, x, y, MINI_TILEX, MINI_TILEY);
780 }
781
782 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
783                         int cut_mode, int mask_mode)
784 {
785   int width = TILEX, height = TILEY;
786   int cx = 0, cy = 0;
787   int src_x, src_y, dest_x, dest_y;
788   int tile = graphic;
789   Pixmap src_pixmap;
790   GC drawing_gc;
791
792   if (graphic < 0)
793   {
794     DrawGraphic(x, y, graphic);
795     return;
796   }
797
798   if (dx || dy)                 /* Verschiebung der Grafik? */
799   {
800     if (x < BX1)                /* Element kommt von links ins Bild */
801     {
802       x = BX1;
803       width = dx;
804       cx = TILEX - dx;
805       dx = 0;
806     }
807     else if (x > BX2)           /* Element kommt von rechts ins Bild */
808     {
809       x = BX2;
810       width = -dx;
811       dx = TILEX + dx;
812     }
813     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
814     {
815       width += dx;
816       cx = -dx;
817       dx = 0;
818     }
819     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
820       width -= dx;
821     else if (dx)                /* allg. Bewegung in x-Richtung */
822       MarkTileDirty(x + SIGN(dx), y);
823
824     if (y < BY1)                /* Element kommt von oben ins Bild */
825     {
826       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
827         return;
828
829       y = BY1;
830       height = dy;
831       cy = TILEY - dy;
832       dy = 0;
833     }
834     else if (y > BY2)           /* Element kommt von unten ins Bild */
835     {
836       y = BY2;
837       height = -dy;
838       dy = TILEY + dy;
839     }
840     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
841     {
842       height += dy;
843       cy = -dy;
844       dy = 0;
845     }
846     else if (dy > 0 && cut_mode == CUT_ABOVE)
847     {
848       if (y == BY2)             /* Element unterhalb des Bildes */
849         return;
850
851       height = dy;
852       cy = TILEY - dy;
853       dy = TILEY;
854       MarkTileDirty(x, y + 1);
855     }                           /* Element verläßt unten das Bild */
856     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
857       height -= dy;
858     else if (dy)                /* allg. Bewegung in y-Richtung */
859       MarkTileDirty(x, y + SIGN(dy));
860   }
861
862   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
863   {
864     src_pixmap = pix[PIX_BACK];
865     drawing_gc = clip_gc[PIX_BACK];
866     graphic -= GFX_START_ROCKSSCREEN;
867     src_x  = SX + (graphic % GFX_PER_LINE) * TILEX + cx;
868     src_y  = SY + (graphic / GFX_PER_LINE) * TILEY + cy;
869   }
870   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
871   {
872     src_pixmap = pix[PIX_MORE];
873     drawing_gc = clip_gc[PIX_MORE];
874     graphic -= GFX_START_ROCKSMORE;
875     src_x  = (graphic % MORE_PER_LINE) * TILEX + cx;
876     src_y  = (graphic / MORE_PER_LINE) * TILEY + cy;
877   }
878   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
879   {
880     src_pixmap = pix[PIX_HEROES];
881     drawing_gc = clip_gc[PIX_HEROES];
882     graphic -= GFX_START_ROCKSHEROES;
883     src_x  = (graphic % HEROES_PER_LINE) * TILEX + cx;
884     src_y  = (graphic / HEROES_PER_LINE) * TILEY + cy;
885   }
886   else  /* big font graphics currently not allowed (and not needed) */
887     return;
888
889   dest_x = FX + x * TILEX + dx;
890   dest_y = FY + y * TILEY + dy;
891
892 #if DEBUG
893   if (!IN_SCR_FIELD(x,y))
894   {
895     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
896     printf("DrawGraphicShifted(): This should never happen!\n");
897     return;
898   }
899 #endif
900
901   if (mask_mode == USE_MASKING)
902   {
903     if (tile_clipmask[tile] != None)
904     {
905       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
906       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
907       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
908                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
909     }
910     else
911     {
912 #if DEBUG
913       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
914 #endif
915
916       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
917       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
918                 src_x, src_y, width, height, dest_x, dest_y);
919     }
920   }
921   else
922     XCopyArea(display, src_pixmap, drawto_field, gc,
923               src_x, src_y, width, height, dest_x, dest_y);
924
925   MarkTileDirty(x,y);
926 }
927
928 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
929                                 int cut_mode)
930 {
931   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
932 }
933
934 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
935                           int cut_mode, int mask_mode)
936 {
937   int ux = LEVELX(x), uy = LEVELY(y);
938   int graphic = el2gfx(element);
939   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
940   int phase4 = phase8 / 2;
941   int phase2  = phase8 / 4;
942   int dir = MovDir[ux][uy];
943
944   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
945   {
946     graphic += 4 * !phase2;
947
948     if (dir == MV_UP)
949       graphic += 1;
950     else if (dir == MV_LEFT)
951       graphic += 2;
952     else if (dir == MV_DOWN)
953       graphic += 3;
954   }
955   else if (element == EL_SP_SNIKSNAK)
956   {
957     if (dir == MV_LEFT)
958       graphic = GFX_SP_SNIKSNAK_LEFT;
959     else if (dir == MV_RIGHT)
960       graphic = GFX_SP_SNIKSNAK_RIGHT;
961     else if (dir == MV_UP)
962       graphic = GFX_SP_SNIKSNAK_UP;
963     else
964       graphic = GFX_SP_SNIKSNAK_DOWN;
965
966     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
967   }
968   else if (element == EL_SP_ELECTRON)
969   {
970     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
971   }
972   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
973            element == EL_SCHWEIN || element == EL_DRACHE)
974   {
975     if (dir == MV_LEFT)
976       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
977                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
978                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
979     else if (dir == MV_RIGHT)
980       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
981                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
982                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
983     else if (dir == MV_UP)
984       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
985                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
986                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
987     else
988       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
989                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
990                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
991
992     graphic += phase4;
993   }
994   else if (element == EL_SONDE)
995   {
996     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
997   }
998   else if (element == EL_SALZSAEURE)
999   {
1000     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1001   }
1002   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1003   {
1004     graphic += !phase2;
1005   }
1006   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
1007   {
1008     if (element != EL_SP_INFOTRON)
1009       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1010   }
1011   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1012            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1013   {
1014     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1015   }
1016   else if (IS_AMOEBOID(element))
1017   {
1018     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1019     graphic += (x + 2 * y + 4) % 4;
1020   }
1021   else if (element == EL_MAUER_LEBT)
1022   {
1023     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1024
1025     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1026       links_massiv = TRUE;
1027     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1028       rechts_massiv = TRUE;
1029
1030     if (links_massiv && rechts_massiv)
1031       graphic = GFX_MAUERWERK;
1032     else if (links_massiv)
1033       graphic = GFX_MAUER_R;
1034     else if (rechts_massiv)
1035       graphic = GFX_MAUER_L;
1036   }
1037
1038   if (dx || dy)
1039     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1040   else if (mask_mode == USE_MASKING)
1041     DrawGraphicThruMask(x, y, graphic);
1042   else
1043     DrawGraphic(x, y, graphic);
1044 }
1045
1046 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1047                          int cut_mode, int mask_mode)
1048 {
1049   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1050     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1051                          cut_mode, mask_mode);
1052 }
1053
1054 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1055                               int cut_mode)
1056 {
1057   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1058 }
1059
1060 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1061                              int cut_mode)
1062 {
1063   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1064 }
1065
1066 void DrawScreenElementThruMask(int x, int y, int element)
1067 {
1068   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1069 }
1070
1071 void DrawLevelElementThruMask(int x, int y, int element)
1072 {
1073   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1074 }
1075
1076 void DrawLevelFieldThruMask(int x, int y)
1077 {
1078   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1079 }
1080
1081 void ErdreichAnbroeckeln(int x, int y)
1082 {
1083   int i, width, height, cx,cy;
1084   int ux = LEVELX(x), uy = LEVELY(y);
1085   int element, graphic;
1086   int snip = 4;
1087   static int xy[4][2] =
1088   {
1089     { 0, -1 },
1090     { -1, 0 },
1091     { +1, 0 },
1092     { 0, +1 }
1093   };
1094
1095   if (!IN_LEV_FIELD(ux, uy))
1096     return;
1097
1098   element = Feld[ux][uy];
1099
1100   if (element == EL_ERDREICH)
1101   {
1102     if (!IN_SCR_FIELD(x, y))
1103       return;
1104
1105     graphic = GFX_ERDENRAND;
1106
1107     for(i=0; i<4; i++)
1108     {
1109       int uxx, uyy;
1110
1111       uxx = ux + xy[i][0];
1112       uyy = uy + xy[i][1];
1113       if (!IN_LEV_FIELD(uxx, uyy))
1114         element = EL_BETON;
1115       else
1116         element = Feld[uxx][uyy];
1117
1118       if (element == EL_ERDREICH)
1119         continue;
1120
1121       if (i == 1 || i == 2)
1122       {
1123         width = snip;
1124         height = TILEY;
1125         cx = (i == 2 ? TILEX - snip : 0);
1126         cy = 0;
1127       }
1128       else
1129       {
1130         width = TILEX;
1131         height = snip;
1132         cx = 0;
1133         cy = (i == 3 ? TILEY - snip : 0);
1134       }
1135
1136       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1137                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1138                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1139                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1140     }
1141
1142     MarkTileDirty(x, y);
1143   }
1144   else
1145   {
1146     graphic = GFX_ERDENRAND;
1147
1148     for(i=0; i<4; i++)
1149     {
1150       int xx, yy, uxx, uyy;
1151
1152       xx = x + xy[i][0];
1153       yy = y + xy[i][1];
1154       uxx = ux + xy[i][0];
1155       uyy = uy + xy[i][1];
1156
1157       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1158           !IN_SCR_FIELD(xx, yy))
1159         continue;
1160
1161       if (i == 1 || i == 2)
1162       {
1163         width = snip;
1164         height = TILEY;
1165         cx = (i == 1 ? TILEX - snip : 0);
1166         cy = 0;
1167       }
1168       else
1169       {
1170         width = TILEX;
1171         height = snip;
1172         cx = 0;
1173         cy = (i==0 ? TILEY-snip : 0);
1174       }
1175
1176       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1177                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1178                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1179                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1180
1181       MarkTileDirty(xx, yy);
1182     }
1183   }
1184 }
1185
1186 void DrawScreenElement(int x, int y, int element)
1187 {
1188   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1189   ErdreichAnbroeckeln(x, y);
1190 }
1191
1192 void DrawLevelElement(int x, int y, int element)
1193 {
1194   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1195     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1196 }
1197
1198 void DrawScreenField(int x, int y)
1199 {
1200   int ux = LEVELX(x), uy = LEVELY(y);
1201   int element;
1202
1203   if (!IN_LEV_FIELD(ux, uy))
1204   {
1205     DrawScreenElement(x, y, EL_BETON);
1206     return;
1207   }
1208
1209   element = Feld[ux][uy];
1210
1211   if (IS_MOVING(ux, uy))
1212   {
1213     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1214     boolean cut_mode = NO_CUTTING;
1215
1216     if (Store[ux][uy] == EL_MORAST_LEER ||
1217         Store[ux][uy] == EL_SIEB_LEER ||
1218         Store[ux][uy] == EL_SIEB2_LEER ||
1219         Store[ux][uy] == EL_AMOEBE_NASS)
1220       cut_mode = CUT_ABOVE;
1221     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1222              Store[ux][uy] == EL_SIEB_VOLL ||
1223              Store[ux][uy] == EL_SIEB2_VOLL)
1224       cut_mode = CUT_BELOW;
1225
1226     if (cut_mode == CUT_ABOVE)
1227       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1228     else
1229       DrawScreenElement(x, y, EL_LEERRAUM);
1230
1231     if (horiz_move)
1232       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1233     else
1234       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1235
1236     if (Store[ux][uy] == EL_SALZSAEURE)
1237       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1238   }
1239   else if (IS_BLOCKED(ux, uy))
1240   {
1241     int oldx, oldy;
1242     int sx, sy;
1243     int horiz_move;
1244     boolean cut_mode = NO_CUTTING;
1245
1246     Blocked2Moving(ux, uy, &oldx, &oldy);
1247     sx = SCREENX(oldx);
1248     sy = SCREENY(oldy);
1249     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1250                   MovDir[oldx][oldy] == MV_RIGHT);
1251
1252     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1253         Store[oldx][oldy] == EL_SIEB_LEER ||
1254         Store[oldx][oldy] == EL_SIEB2_LEER ||
1255         Store[oldx][oldy] == EL_AMOEBE_NASS)
1256       cut_mode = CUT_ABOVE;
1257
1258     DrawScreenElement(x, y, EL_LEERRAUM);
1259     element = Feld[oldx][oldy];
1260
1261     if (horiz_move)
1262       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1263     else
1264       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1265   }
1266   else if (IS_DRAWABLE(element))
1267     DrawScreenElement(x, y, element);
1268   else
1269     DrawScreenElement(x, y, EL_LEERRAUM);
1270 }
1271
1272 void DrawLevelField(int x, int y)
1273 {
1274   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1275     DrawScreenField(SCREENX(x), SCREENY(y));
1276   else if (IS_MOVING(x, y))
1277   {
1278     int newx,newy;
1279
1280     Moving2Blocked(x, y, &newx, &newy);
1281     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1282       DrawScreenField(SCREENX(newx), SCREENY(newy));
1283   }
1284   else if (IS_BLOCKED(x, y))
1285   {
1286     int oldx, oldy;
1287
1288     Blocked2Moving(x, y, &oldx, &oldy);
1289     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1290       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1291   }
1292 }
1293
1294 void DrawMiniElement(int x, int y, int element)
1295 {
1296   int graphic;
1297
1298   if (!element)
1299   {
1300     DrawMiniGraphic(x, y, -1);
1301     return;
1302   }
1303
1304   graphic = el2gfx(element);
1305   DrawMiniGraphic(x, y, graphic);
1306 }
1307
1308 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1309 {
1310   int x = sx + scroll_x, y = sy + scroll_y;
1311
1312   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1313     DrawMiniElement(sx, sy, EL_LEERRAUM);
1314   else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy)
1315     DrawMiniElement(sx, sy, EL_BETON);
1316   else
1317     DrawMiniElement(sx, sy, Feld[x][y]);
1318 }
1319
1320 void DrawMicroElement(int xpos, int ypos, int element)
1321 {
1322   int graphic;
1323
1324   if (element == EL_LEERRAUM)
1325     return;
1326
1327   graphic = el2gfx(element);
1328
1329   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1330   {
1331     graphic -= GFX_START_ROCKSMORE;
1332     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1333               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1334               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1335               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1336   }
1337   else
1338     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1339               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1340               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1341               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1342 }
1343
1344 void DrawLevel()
1345 {
1346   int x,y;
1347
1348   ClearWindow();
1349
1350   for(x=BX1; x<=BX2; x++)
1351     for(y=BY1; y<=BY2; y++)
1352       DrawScreenField(x, y);
1353
1354   if (setup.soft_scrolling)
1355     XCopyArea(display, fieldbuffer, backbuffer, gc,
1356               FX, FY, SXSIZE, SYSIZE, SX, SY);
1357
1358   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1359 }
1360
1361 void DrawMiniLevel(int scroll_x, int scroll_y)
1362 {
1363   int x,y;
1364
1365   ClearWindow();
1366
1367   for(x=0; x<2*SCR_FIELDX; x++)
1368     for(y=0; y<2*SCR_FIELDY; y++)
1369       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1370
1371   redraw_mask |= REDRAW_FIELD;
1372 }
1373
1374 void DrawMicroLevel(int xpos, int ypos)
1375 {
1376   int x,y;
1377
1378   XFillRectangle(display, drawto, gc,
1379                  xpos - MICRO_TILEX, ypos - MICRO_TILEY,
1380                  MICRO_TILEX * (STD_LEV_FIELDX + 2),
1381                  MICRO_TILEY * (STD_LEV_FIELDY + 2));
1382   if (lev_fieldx < STD_LEV_FIELDX)
1383     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1384   if (lev_fieldy < STD_LEV_FIELDY)
1385     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1386
1387   for(x=-1; x<=STD_LEV_FIELDX; x++)
1388     for(y=-1; y<=STD_LEV_FIELDY; y++)
1389       if (x >= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy)
1390         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1391                          Ur[x][y]);
1392       else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1)
1393         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1394                          EL_BETON);
1395
1396   XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1397
1398   if (level.name)
1399   {
1400     int len = strlen(level.name);
1401     int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1402     int lypos = MICROLABEL_YPOS;
1403
1404     DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1405   }
1406
1407   redraw_mask |= REDRAW_MICROLEV;
1408 }
1409
1410 int REQ_in_range(int x, int y)
1411 {
1412   if (y > DY+249 && y < DY+278)
1413   {
1414     if (x > DX+1 && x < DX+48)
1415       return 1;
1416     else if (x > DX+51 && x < DX+98) 
1417       return 2;
1418   }
1419   return 0;
1420 }
1421
1422 boolean Request(char *text, unsigned int req_state)
1423 {
1424   int mx, my, ty, result = -1;
1425   unsigned int old_door_state;
1426
1427 #ifndef MSDOS
1428   /* pause network game while waiting for request to answer */
1429   if (options.network &&
1430       game_status == PLAYING &&
1431       req_state & REQUEST_WAIT_FOR)
1432     SendToServer_PausePlaying();
1433 #endif
1434
1435   old_door_state = GetDoorState();
1436
1437   CloseDoor(DOOR_CLOSE_1);
1438
1439   /* Alten Türinhalt sichern */
1440   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1441             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1442             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1443
1444   /* Fragetext schreiben */
1445   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1446                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1447
1448   for(ty=0; ty<13; ty++)
1449   {
1450     int tx, tl, tc;
1451     char txt[256];
1452
1453     if (!*text)
1454       break;
1455
1456     for(tl=0,tx=0; tx<7; tl++,tx++)
1457     {
1458       tc = *(text + tx);
1459       if (!tc || tc == 32)
1460         break;
1461     }
1462     if (!tl)
1463     { 
1464       text++; 
1465       ty--; 
1466       continue; 
1467     }
1468     sprintf(txt, text); 
1469     txt[tl] = 0;
1470     DrawTextExt(pix[PIX_DB_DOOR], gc,
1471                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1472                 txt, FS_SMALL, FC_YELLOW);
1473     text += tl + (tc == 32 ? 1 : 0);
1474   }
1475
1476   if (req_state & REQ_ASK)
1477   {
1478     DrawYesNoButton(BUTTON_OK, DB_INIT);
1479     DrawYesNoButton(BUTTON_NO, DB_INIT);
1480   }
1481   else if (req_state & REQ_CONFIRM)
1482   {
1483     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1484   }
1485   else if (req_state & REQ_PLAYER)
1486   {
1487     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1488     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1489     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1490     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1491   }
1492
1493   OpenDoor(DOOR_OPEN_1);
1494   ClearEventQueue();
1495
1496   if (!(req_state & REQUEST_WAIT_FOR))
1497     return(FALSE);
1498
1499   if (game_status != MAINMENU)
1500     InitAnimation();
1501
1502   button_status = MB_RELEASED;
1503
1504   while(result < 0)
1505   {
1506     if (XPending(display))
1507     {
1508       XEvent event;
1509
1510       XNextEvent(display, &event);
1511
1512       switch(event.type)
1513       {
1514         case ButtonPress:
1515         case ButtonRelease:
1516         case MotionNotify:
1517         {
1518           int choice;
1519
1520           if (event.type == MotionNotify)
1521           {
1522             motion_status = TRUE;
1523             mx = ((XMotionEvent *) &event)->x;
1524             my = ((XMotionEvent *) &event)->y;
1525           }
1526           else
1527           {
1528             motion_status = FALSE;
1529             mx = ((XButtonEvent *) &event)->x;
1530             my = ((XButtonEvent *) &event)->y;
1531             if (event.type==ButtonPress)
1532               button_status = ((XButtonEvent *) &event)->button;
1533             else
1534               button_status = MB_RELEASED;
1535           }
1536
1537           if (req_state & REQ_ASK)
1538             choice = CheckYesNoButtons(mx,my,button_status);
1539           else if (req_state & REQ_CONFIRM)
1540             choice = CheckConfirmButton(mx,my,button_status);
1541           else
1542             choice = CheckPlayerButtons(mx,my,button_status);
1543
1544           switch(choice)
1545           {
1546             case BUTTON_OK:
1547               result = TRUE;
1548               break;
1549             case BUTTON_NO:
1550               result = FALSE;
1551               break;
1552             case BUTTON_CONFIRM:
1553               result = TRUE | FALSE;
1554               break;
1555
1556             case BUTTON_PLAYER_1:
1557               result = 1;
1558               break;
1559             case BUTTON_PLAYER_2:
1560               result = 2;
1561               break;
1562             case BUTTON_PLAYER_3:
1563               result = 3;
1564               break;
1565             case BUTTON_PLAYER_4:
1566               result = 4;
1567               break;
1568
1569             default:
1570               break;
1571           }
1572           break;
1573         }
1574
1575         case KeyPress:
1576           switch(XLookupKeysym((XKeyEvent *)&event,
1577                                ((XKeyEvent *)&event)->state))
1578           {
1579             case XK_Return:
1580               result = 1;
1581               break;
1582
1583             case XK_Escape:
1584               result = 0;
1585               break;
1586
1587             default:
1588               break;
1589           }
1590           if (req_state & REQ_PLAYER)
1591             result = 0;
1592           break;
1593
1594         case KeyRelease:
1595           key_joystick_mapping = 0;
1596           break;
1597
1598         default:
1599           HandleOtherEvents(&event);
1600           break;
1601       }
1602     }
1603     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1604     {
1605       int joy = AnyJoystick();
1606
1607       if (joy & JOY_BUTTON_1)
1608         result = 1;
1609       else if (joy & JOY_BUTTON_2)
1610         result = 0;
1611     }
1612
1613     DoAnimation();
1614
1615     /* don't eat all CPU time */
1616     Delay(10);
1617   }
1618
1619   if (game_status != MAINMENU)
1620     StopAnimation();
1621
1622   if (!(req_state & REQ_STAY_OPEN))
1623   {
1624     CloseDoor(DOOR_CLOSE_1);
1625
1626     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1627     {
1628       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1629                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1630                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1631       OpenDoor(DOOR_OPEN_1);
1632     }
1633   }
1634
1635 #ifndef MSDOS
1636   /* continue network game after request */
1637   if (options.network &&
1638       game_status == PLAYING &&
1639       req_state & REQUEST_WAIT_FOR)
1640     SendToServer_ContinuePlaying();
1641 #endif
1642
1643   return(result);
1644 }
1645
1646 unsigned int OpenDoor(unsigned int door_state)
1647 {
1648   unsigned int new_door_state;
1649
1650   if (door_state & DOOR_COPY_BACK)
1651   {
1652     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1653               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1654               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1655     door_state &= ~DOOR_COPY_BACK;
1656   }
1657
1658   new_door_state = MoveDoor(door_state);
1659
1660   return(new_door_state);
1661 }
1662
1663 unsigned int CloseDoor(unsigned int door_state)
1664 {
1665   unsigned int new_door_state;
1666
1667   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1668             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1669   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1670             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1671
1672   new_door_state = MoveDoor(door_state);
1673
1674   return(new_door_state);
1675 }
1676
1677 unsigned int GetDoorState()
1678 {
1679   return(MoveDoor(DOOR_GET_STATE));
1680 }
1681
1682 unsigned int MoveDoor(unsigned int door_state)
1683 {
1684   static int door1 = DOOR_OPEN_1;
1685   static int door2 = DOOR_CLOSE_2;
1686   static unsigned long door_delay = 0;
1687   int x, start, stepsize = 2;
1688   unsigned long door_delay_value = stepsize * 5;
1689
1690   if (door_state == DOOR_GET_STATE)
1691     return(door1 | door2);
1692
1693   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1694     door_state &= ~DOOR_OPEN_1;
1695   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1696     door_state &= ~DOOR_CLOSE_1;
1697   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1698     door_state &= ~DOOR_OPEN_2;
1699   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1700     door_state &= ~DOOR_CLOSE_2;
1701
1702   if (setup.quick_doors)
1703   {
1704     stepsize = 20;
1705     door_delay_value = 0;
1706     StopSound(SND_OEFFNEN);
1707   }
1708
1709   if (door_state & DOOR_ACTION)
1710   {
1711     if (!(door_state & DOOR_NO_DELAY))
1712       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1713
1714     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1715
1716     for(x=start; x<=DXSIZE; x+=stepsize)
1717     {
1718       WaitUntilDelayReached(&door_delay, door_delay_value);
1719
1720       if (door_state & DOOR_ACTION_1)
1721       {
1722         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1723         int j = (DXSIZE - i) / 3;
1724
1725         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1726                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1727                   DXSIZE,DYSIZE - i/2, DX, DY);
1728
1729         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1730
1731         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1732                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1733         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1734                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1735         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1736                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1737                   DY + 140 + j);
1738         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1739                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1740         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1741                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1742         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1743                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1744
1745         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1746                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1747                   DX, DY + 77 - j);
1748         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1749                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1750                   DX, DY + 203 - j);
1751         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1752                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1753         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1754                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1755                   DX + DXSIZE - i, DY + 77 + j);
1756         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1757                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1758                   DX + DXSIZE - i, DY + 203 + j);
1759
1760         redraw_mask |= REDRAW_DOOR_1;
1761       }
1762
1763       if (door_state & DOOR_ACTION_2)
1764       {
1765         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1766         int j = (VXSIZE - i) / 3;
1767
1768         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1769                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1770                   VXSIZE, VYSIZE - i/2, VX, VY);
1771
1772         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1773
1774         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1775                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1776         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1777                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1778         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1779                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1780         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1781                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1782
1783         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1784                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1785                   VX, VY + VYSIZE / 2 - j);
1786         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1787                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1788         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1789                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1790                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1791
1792         redraw_mask |= REDRAW_DOOR_2;
1793       }
1794
1795       BackToFront();
1796
1797       if (game_status == MAINMENU)
1798         DoAnimation();
1799     }
1800   }
1801
1802   if (setup.quick_doors)
1803     StopSound(SND_OEFFNEN);
1804
1805   if (door_state & DOOR_ACTION_1)
1806     door1 = door_state & DOOR_ACTION_1;
1807   if (door_state & DOOR_ACTION_2)
1808     door2 = door_state & DOOR_ACTION_2;
1809
1810   return(door1 | door2);
1811 }
1812
1813 int ReadPixel(Drawable d, int x, int y)
1814 {
1815   XImage *pixel_image;
1816   unsigned long pixel_value;
1817
1818   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1819   pixel_value = XGetPixel(pixel_image, 0, 0);
1820
1821   XDestroyImage(pixel_image);
1822
1823   return pixel_value;
1824 }
1825
1826 int el2gfx(int element)
1827 {
1828   switch(element)
1829   {
1830     case EL_LEERRAUM:           return -1;
1831     case EL_ERDREICH:           return GFX_ERDREICH;
1832     case EL_MAUERWERK:          return GFX_MAUERWERK;
1833     case EL_FELSBODEN:          return GFX_FELSBODEN;
1834     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1835     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1836     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1837     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1838     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1839     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1840     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1841     case EL_SPIELER1:           return GFX_SPIELER1;
1842     case EL_SPIELER2:           return GFX_SPIELER2;
1843     case EL_SPIELER3:           return GFX_SPIELER3;
1844     case EL_SPIELER4:           return GFX_SPIELER4;
1845     case EL_KAEFER:             return GFX_KAEFER;
1846     case EL_KAEFER_R:           return GFX_KAEFER_R;
1847     case EL_KAEFER_O:           return GFX_KAEFER_O;
1848     case EL_KAEFER_L:           return GFX_KAEFER_L;
1849     case EL_KAEFER_U:           return GFX_KAEFER_U;
1850     case EL_FLIEGER:            return GFX_FLIEGER;
1851     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1852     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1853     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1854     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1855     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1856     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1857     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1858     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1859     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1860     case EL_FIREFLY:            return GFX_FIREFLY;
1861     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1862     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1863     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1864     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1865     case EL_MAMPFER:            return GFX_MAMPFER;
1866     case EL_ROBOT:              return GFX_ROBOT;
1867     case EL_BETON:              return GFX_BETON;
1868     case EL_DIAMANT:            return GFX_DIAMANT;
1869     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1870     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1871     case EL_TROPFEN:            return GFX_TROPFEN;
1872     case EL_BOMBE:              return GFX_BOMBE;
1873     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
1874     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1875     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1876     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1877     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1878     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1879     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1880     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1881     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1882     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1883     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1884     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1885     case EL_LIFE:               return GFX_LIFE;
1886     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1887     case EL_DYNAMIT:            return GFX_DYNAMIT;
1888     case EL_BADEWANNE:          return GFX_BADEWANNE;
1889     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1890     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1891     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
1892     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
1893     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
1894     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
1895     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
1896     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
1897     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
1898     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
1899     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
1900     case EL_PFORTE1:            return GFX_PFORTE1;
1901     case EL_PFORTE2:            return GFX_PFORTE2;
1902     case EL_PFORTE3:            return GFX_PFORTE3;
1903     case EL_PFORTE4:            return GFX_PFORTE4;
1904     case EL_PFORTE1X:           return GFX_PFORTE1X;
1905     case EL_PFORTE2X:           return GFX_PFORTE2X;
1906     case EL_PFORTE3X:           return GFX_PFORTE3X;
1907     case EL_PFORTE4X:           return GFX_PFORTE4X;
1908     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
1909     case EL_PACMAN:             return GFX_PACMAN;
1910     case EL_PACMAN_R:           return GFX_PACMAN_R;
1911     case EL_PACMAN_O:           return GFX_PACMAN_O;
1912     case EL_PACMAN_L:           return GFX_PACMAN_L;
1913     case EL_PACMAN_U:           return GFX_PACMAN_U;
1914     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
1915     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
1916     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
1917     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
1918     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
1919     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
1920     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
1921     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
1922     case EL_MAUER_X:            return GFX_MAUER_X;
1923     case EL_MAUER_Y:            return GFX_MAUER_Y;
1924     case EL_MAUER_XY:           return GFX_MAUER_XY;
1925     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
1926     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
1927     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
1928     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
1929     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
1930     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
1931     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
1932     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
1933     case EL_MAMPFER2:           return GFX_MAMPFER2;
1934     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
1935     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
1936     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
1937     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
1938     case EL_DYNABOMB:           return GFX_DYNABOMB;
1939     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
1940     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
1941     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
1942     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
1943     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
1944     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
1945     case EL_MAULWURF:           return GFX_MAULWURF;
1946     case EL_PINGUIN:            return GFX_PINGUIN;
1947     case EL_SCHWEIN:            return GFX_SCHWEIN;
1948     case EL_DRACHE:             return GFX_DRACHE;
1949     case EL_SONDE:              return GFX_SONDE;
1950     case EL_PFEIL_L:            return GFX_PFEIL_L;
1951     case EL_PFEIL_R:            return GFX_PFEIL_R;
1952     case EL_PFEIL_O:            return GFX_PFEIL_O;
1953     case EL_PFEIL_U:            return GFX_PFEIL_U;
1954     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
1955     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
1956
1957     default:
1958     {
1959       if (IS_CHAR(element))
1960         return GFX_CHAR_START + (element - EL_CHAR_START);
1961       else if (element >= EL_SP_START && element <= EL_SP_END)
1962       {
1963         int nr_element = element - EL_SP_START;
1964         int gfx_per_line = 8;
1965         int nr_graphic =
1966           (nr_element / gfx_per_line) * MORE_PER_LINE +
1967           (nr_element % gfx_per_line);
1968
1969         return GFX_START_ROCKSMORE + nr_graphic;
1970       }
1971       else
1972         return -1;
1973     }
1974   }
1975 }