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