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