rnd-19981204-1
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #ifdef __FreeBSD__
17 #include <machine/joystick.h>
18 #endif
19
20 #include "tools.h"
21 #include "game.h"
22 #include "events.h"
23 #include "sound.h"
24 #include "misc.h"
25 #include "buttons.h"
26 #include "joystick.h"
27 #include "cartoons.h"
28 #include "network.h"
29
30 #ifdef MSDOS
31 extern boolean wait_for_vsync;
32 #endif
33
34 void SetDrawtoField(int mode)
35 {
36   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
37   {
38     FX = TILEX;
39     FY = TILEY;
40     BX1 = -1;
41     BY1 = -1;
42     BX2 = SCR_FIELDX;
43     BY2 = SCR_FIELDY;
44     redraw_x1 = 1;
45     redraw_y1 = 1;
46
47     drawto_field = fieldbuffer;
48   }
49   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
50   {
51     FX = SX;
52     FY = SY;
53     BX1 = 0;
54     BY1 = 0;
55     BX2 = SCR_FIELDX - 1;
56     BY2 = SCR_FIELDY - 1;
57     redraw_x1 = 0;
58     redraw_y1 = 0;
59
60     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
61   }
62 }
63
64 void BackToFront()
65 {
66   int x,y;
67   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
68
69   if (setup.direct_draw && game_status == PLAYING)
70     redraw_mask &= ~REDRAW_MAIN;
71
72   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
73     redraw_mask |= REDRAW_FIELD;
74
75   if (redraw_mask & REDRAW_FIELD)
76     redraw_mask &= ~REDRAW_TILES;
77
78   /*
79   if (redraw_mask & REDRAW_FIELD ||
80       (ScreenGfxPos && setup.soft_scrolling && game_status == PLAYING))
81     redraw_mask &= ~REDRAW_TILES;
82   */
83
84   if (!redraw_mask)
85     return;
86
87   /* synchronize X11 graphics at this point; if we would synchronize the
88      display immediately after the buffer switching (after the XFlush),
89      this could mean that we have to wait for the graphics to complete,
90      although we could go on doing calculations for the next frame */
91
92   XSync(display, FALSE);
93
94   /*
95 #ifdef MSDOS
96   wait_for_vsync = TRUE;
97 #endif
98   */
99
100   if (redraw_mask & REDRAW_ALL)
101   {
102     XCopyArea(display,backbuffer,window,gc,
103               0,0, WIN_XSIZE,WIN_YSIZE,
104               0,0);
105     redraw_mask = 0;
106   }
107
108   if (redraw_mask & REDRAW_FIELD)
109   {
110     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
111       XCopyArea(display,backbuffer,window,gc,
112                 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
113                 REAL_SX,REAL_SY);
114     else
115     {
116       int fx = FX, fy = FY;
117
118       if (setup.soft_scrolling)
119       {
120         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
121         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
122       }
123
124       if (setup.soft_scrolling ||
125           ABS(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   else  /* big font graphics currently not allowed (and not needed) */
835     return;
836
837   dest_x = FX + x * TILEX + dx;
838   dest_y = FY + y * TILEY + dy;
839
840 #if DEBUG
841   if (!IN_SCR_FIELD(x,y))
842   {
843     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
844     printf("DrawGraphicShifted(): This should never happen!\n");
845     return;
846   }
847 #endif
848
849   if (mask_mode == USE_MASKING)
850   {
851     if (tile_clipmask[tile] != None)
852     {
853       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
854       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
855       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
856                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
857     }
858     else
859     {
860 #if DEBUG
861       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
862 #endif
863
864       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
865       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
866                 src_x, src_y, width, height, dest_x, dest_y);
867     }
868   }
869   else
870     XCopyArea(display, src_pixmap, drawto_field, gc,
871               src_x, src_y, width, height, dest_x, dest_y);
872
873   MarkTileDirty(x,y);
874 }
875
876 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
877                                 int cut_mode)
878 {
879   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
880 }
881
882 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
883                           int cut_mode, int mask_mode)
884 {
885   int ux = LEVELX(x), uy = LEVELY(y);
886   int graphic = el2gfx(element);
887   int phase4 = ABS(MovPos[ux][uy]) / (TILEX / 4);
888   int phase  = phase4 / 2;
889   int dir = MovDir[ux][uy];
890
891   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
892   {
893     graphic += 4*!phase;
894
895     if (dir == MV_UP)
896       graphic += 1;
897     else if (dir == MV_LEFT)
898       graphic += 2;
899     else if (dir == MV_DOWN)
900       graphic += 3;
901   }
902   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
903            element == EL_SCHWEIN || element == EL_DRACHE)
904   {
905     if (dir == MV_LEFT)
906       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
907                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
908                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
909     else if (dir == MV_RIGHT)
910       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
911                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
912                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
913     else if (dir == MV_UP)
914       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
915                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
916                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
917     else
918       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
919                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
920                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
921
922     graphic += phase4;
923   }
924   else if (element == EL_SONDE)
925   {
926     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
927   }
928   else if (element == EL_SALZSAEURE)
929   {
930     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
931   }
932   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
933   {
934     graphic += !phase;
935   }
936   else if ((element == EL_FELSBROCKEN || IS_GEM(element)) && !cut_mode)
937   {
938     graphic += phase * (element == EL_FELSBROCKEN ? 2 : 1);
939   }
940   else if ((element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
941             element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL) && SiebAktiv)
942   {
943     graphic += 3 - (SiebAktiv % 8) / 2;
944   }
945   else if (IS_AMOEBOID(element))
946   {
947     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
948     graphic += (x + 2 * y + 4) % 4;
949   }
950   else if (element == EL_MAUER_LEBT)
951   {
952     boolean links_massiv = FALSE, rechts_massiv = FALSE;
953
954     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
955       links_massiv = TRUE;
956     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
957       rechts_massiv = TRUE;
958
959     if (links_massiv && rechts_massiv)
960       graphic = GFX_MAUERWERK;
961     else if (links_massiv)
962       graphic = GFX_MAUER_R;
963     else if (rechts_massiv)
964       graphic = GFX_MAUER_L;
965   }
966
967   if (dx || dy)
968     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
969   else if (mask_mode == USE_MASKING)
970     DrawGraphicThruMask(x, y, graphic);
971   else
972     DrawGraphic(x, y, graphic);
973 }
974
975 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
976                          int cut_mode, int mask_mode)
977 {
978   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
979     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
980                          cut_mode, mask_mode);
981 }
982
983 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
984                               int cut_mode)
985 {
986   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
987 }
988
989 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
990                              int cut_mode)
991 {
992   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
993 }
994
995 void DrawScreenElementThruMask(int x, int y, int element)
996 {
997   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
998 }
999
1000 void DrawLevelElementThruMask(int x, int y, int element)
1001 {
1002   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1003 }
1004
1005 void DrawLevelFieldThruMask(int x, int y)
1006 {
1007   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1008 }
1009
1010 void ErdreichAnbroeckeln(int x, int y)
1011 {
1012   int i, width, height, cx,cy;
1013   int ux = LEVELX(x), uy = LEVELY(y);
1014   int element, graphic;
1015   int snip = 4;
1016   static int xy[4][2] =
1017   {
1018     { 0, -1 },
1019     { -1, 0 },
1020     { +1, 0 },
1021     { 0, +1 }
1022   };
1023
1024   if (!IN_LEV_FIELD(ux, uy))
1025     return;
1026
1027   element = Feld[ux][uy];
1028
1029   if (element == EL_ERDREICH)
1030   {
1031     if (!IN_SCR_FIELD(x, y))
1032       return;
1033
1034     graphic = GFX_ERDENRAND;
1035
1036     for(i=0; i<4; i++)
1037     {
1038       int uxx, uyy;
1039
1040       uxx = ux + xy[i][0];
1041       uyy = uy + xy[i][1];
1042       if (!IN_LEV_FIELD(uxx, uyy))
1043         element = EL_BETON;
1044       else
1045         element = Feld[uxx][uyy];
1046
1047       if (element == EL_ERDREICH)
1048         continue;
1049
1050       if (i == 1 || i == 2)
1051       {
1052         width = snip;
1053         height = TILEY;
1054         cx = (i == 2 ? TILEX - snip : 0);
1055         cy = 0;
1056       }
1057       else
1058       {
1059         width = TILEX;
1060         height = snip;
1061         cx = 0;
1062         cy = (i == 3 ? TILEY - snip : 0);
1063       }
1064
1065       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1066                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1067                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1068                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1069     }
1070
1071     MarkTileDirty(x, y);
1072   }
1073   else
1074   {
1075     graphic = GFX_ERDENRAND;
1076
1077     for(i=0; i<4; i++)
1078     {
1079       int xx, yy, uxx, uyy;
1080
1081       xx = x + xy[i][0];
1082       yy = y + xy[i][1];
1083       uxx = ux + xy[i][0];
1084       uyy = uy + xy[i][1];
1085
1086       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1087           !IN_SCR_FIELD(xx, yy))
1088         continue;
1089
1090       if (i == 1 || i == 2)
1091       {
1092         width = snip;
1093         height = TILEY;
1094         cx = (i == 1 ? TILEX - snip : 0);
1095         cy = 0;
1096       }
1097       else
1098       {
1099         width = TILEX;
1100         height = snip;
1101         cx = 0;
1102         cy = (i==0 ? TILEY-snip : 0);
1103       }
1104
1105       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1106                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1107                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1108                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1109
1110       MarkTileDirty(xx, yy);
1111     }
1112   }
1113 }
1114
1115 void DrawScreenElement(int x, int y, int element)
1116 {
1117   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1118   ErdreichAnbroeckeln(x, y);
1119 }
1120
1121 void DrawLevelElement(int x, int y, int element)
1122 {
1123   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1124     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1125 }
1126
1127 void DrawScreenField(int x, int y)
1128 {
1129   int ux = LEVELX(x), uy = LEVELY(y);
1130   int element;
1131
1132   if (!IN_LEV_FIELD(ux, uy))
1133   {
1134     DrawScreenElement(x, y, EL_BETON);
1135     return;
1136   }
1137
1138   element = Feld[ux][uy];
1139
1140   if (IS_MOVING(ux, uy))
1141   {
1142     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1143     boolean cut_mode = NO_CUTTING;
1144
1145     if (Store[ux][uy] == EL_MORAST_LEER ||
1146         Store[ux][uy] == EL_SIEB_LEER ||
1147         Store[ux][uy] == EL_SIEB2_LEER ||
1148         Store[ux][uy] == EL_AMOEBE_NASS)
1149       cut_mode = CUT_ABOVE;
1150     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1151              Store[ux][uy] == EL_SIEB_VOLL ||
1152              Store[ux][uy] == EL_SIEB2_VOLL)
1153       cut_mode = CUT_BELOW;
1154
1155     if (cut_mode == CUT_ABOVE)
1156       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1157     else
1158       DrawScreenElement(x, y, EL_LEERRAUM);
1159
1160     if (horiz_move)
1161       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1162     else
1163       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1164
1165     if (Store[ux][uy] == EL_SALZSAEURE)
1166       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1167   }
1168   else if (IS_BLOCKED(ux, uy))
1169   {
1170     int oldx, oldy;
1171     int sx, sy;
1172     int horiz_move;
1173     boolean cut_mode = NO_CUTTING;
1174
1175     Blocked2Moving(ux, uy, &oldx, &oldy);
1176     sx = SCREENX(oldx);
1177     sy = SCREENY(oldy);
1178     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1179                   MovDir[oldx][oldy] == MV_RIGHT);
1180
1181     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1182         Store[oldx][oldy] == EL_SIEB_LEER ||
1183         Store[oldx][oldy] == EL_SIEB2_LEER ||
1184         Store[oldx][oldy] == EL_AMOEBE_NASS)
1185       cut_mode = CUT_ABOVE;
1186
1187     DrawScreenElement(x, y, EL_LEERRAUM);
1188     element = Feld[oldx][oldy];
1189
1190     if (horiz_move)
1191       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1192     else
1193       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1194   }
1195   else if (IS_DRAWABLE(element))
1196     DrawScreenElement(x, y, element);
1197   else
1198     DrawScreenElement(x, y, EL_LEERRAUM);
1199 }
1200
1201 void DrawLevelField(int x, int y)
1202 {
1203   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1204     DrawScreenField(SCREENX(x), SCREENY(y));
1205   else if (IS_MOVING(x, y))
1206   {
1207     int newx,newy;
1208
1209     Moving2Blocked(x, y, &newx, &newy);
1210     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1211       DrawScreenField(SCREENX(newx), SCREENY(newy));
1212   }
1213   else if (IS_BLOCKED(x, y))
1214   {
1215     int oldx, oldy;
1216
1217     Blocked2Moving(x, y, &oldx, &oldy);
1218     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1219       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1220   }
1221 }
1222
1223 void DrawMiniElement(int x, int y, int element)
1224 {
1225   int graphic;
1226
1227   if (!element)
1228   {
1229     DrawMiniGraphic(x, y, -1);
1230     return;
1231   }
1232
1233   graphic = el2gfx(element);
1234   DrawMiniGraphic(x, y, graphic);
1235 }
1236
1237 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1238 {
1239   int x = sx + scroll_x, y = sy + scroll_y;
1240
1241   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1242     DrawMiniElement(sx, sy, EL_LEERRAUM);
1243   else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy)
1244     DrawMiniElement(sx, sy, EL_BETON);
1245   else
1246     DrawMiniElement(sx, sy, Feld[x][y]);
1247 }
1248
1249 void DrawMicroElement(int xpos, int ypos, int element)
1250 {
1251   int graphic;
1252
1253   if (element == EL_LEERRAUM)
1254     return;
1255
1256   graphic = el2gfx(element);
1257
1258   XCopyArea(display, pix[PIX_BACK], drawto, gc,
1259             MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1260             MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1261             MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1262 }
1263
1264 void DrawLevel()
1265 {
1266   int x,y;
1267
1268   ClearWindow();
1269
1270   for(x=BX1; x<=BX2; x++)
1271     for(y=BY1; y<=BY2; y++)
1272       DrawScreenField(x, y);
1273
1274   if (setup.soft_scrolling)
1275     XCopyArea(display, fieldbuffer, backbuffer, gc,
1276               FX, FY, SXSIZE, SYSIZE, SX, SY);
1277
1278   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1279 }
1280
1281 void DrawMiniLevel(int scroll_x, int scroll_y)
1282 {
1283   int x,y;
1284
1285   ClearWindow();
1286
1287   for(x=0; x<2*SCR_FIELDX; x++)
1288     for(y=0; y<2*SCR_FIELDY; y++)
1289       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1290
1291   redraw_mask |= REDRAW_FIELD;
1292 }
1293
1294 void DrawMicroLevel(int xpos, int ypos)
1295 {
1296   int x,y;
1297
1298   XFillRectangle(display, drawto, gc,
1299                  xpos - MICRO_TILEX, ypos - MICRO_TILEY,
1300                  MICRO_TILEX * (STD_LEV_FIELDX + 2),
1301                  MICRO_TILEY * (STD_LEV_FIELDY + 2));
1302   if (lev_fieldx < STD_LEV_FIELDX)
1303     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1304   if (lev_fieldy < STD_LEV_FIELDY)
1305     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1306
1307   for(x=-1; x<=STD_LEV_FIELDX; x++)
1308     for(y=-1; y<=STD_LEV_FIELDY; y++)
1309       if (x >= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy)
1310         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1311                          Ur[x][y]);
1312       else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1)
1313         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1314                          EL_BETON);
1315
1316   XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1317
1318   if (level.name)
1319   {
1320     int len = strlen(level.name);
1321     int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1322     int lypos = MICROLABEL_YPOS;
1323
1324     DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1325   }
1326
1327   redraw_mask |= REDRAW_MICROLEV;
1328 }
1329
1330 int REQ_in_range(int x, int y)
1331 {
1332   if (y > DY+249 && y < DY+278)
1333   {
1334     if (x > DX+1 && x < DX+48)
1335       return 1;
1336     else if (x > DX+51 && x < DX+98) 
1337       return 2;
1338   }
1339   return 0;
1340 }
1341
1342 boolean Request(char *text, unsigned int req_state)
1343 {
1344   int mx, my, ty, result = -1;
1345   unsigned int old_door_state;
1346
1347 #ifndef MSDOS
1348   /* pause network game while waiting for request to answer */
1349   if (options.network &&
1350       game_status == PLAYING &&
1351       req_state & REQUEST_WAIT_FOR)
1352     SendToServer_PausePlaying();
1353 #endif
1354
1355   old_door_state = GetDoorState();
1356
1357   CloseDoor(DOOR_CLOSE_1);
1358
1359   /* Alten Türinhalt sichern */
1360   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1361             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1362             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1363
1364   /* Fragetext schreiben */
1365   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1366                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1367
1368   for(ty=0; ty<13; ty++)
1369   {
1370     int tx, tl, tc;
1371     char txt[256];
1372
1373     if (!*text)
1374       break;
1375
1376     for(tl=0,tx=0; tx<7; tl++,tx++)
1377     {
1378       tc = *(text + tx);
1379       if (!tc || tc == 32)
1380         break;
1381     }
1382     if (!tl)
1383     { 
1384       text++; 
1385       ty--; 
1386       continue; 
1387     }
1388     sprintf(txt, text); 
1389     txt[tl] = 0;
1390     DrawTextExt(pix[PIX_DB_DOOR], gc,
1391                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1392                 txt, FS_SMALL, FC_YELLOW);
1393     text += tl + (tc == 32 ? 1 : 0);
1394   }
1395
1396   if (req_state & REQ_ASK)
1397   {
1398     DrawYesNoButton(BUTTON_OK, DB_INIT);
1399     DrawYesNoButton(BUTTON_NO, DB_INIT);
1400   }
1401   else if (req_state & REQ_CONFIRM)
1402   {
1403     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1404   }
1405   else if (req_state & REQ_PLAYER)
1406   {
1407     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1408     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1409     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1410     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1411   }
1412
1413   OpenDoor(DOOR_OPEN_1);
1414   ClearEventQueue();
1415
1416   if (!(req_state & REQUEST_WAIT_FOR))
1417     return(FALSE);
1418
1419   if (game_status != MAINMENU)
1420     InitAnimation();
1421
1422   button_status = MB_RELEASED;
1423
1424   while(result < 0)
1425   {
1426     if (XPending(display))
1427     {
1428       XEvent event;
1429
1430       XNextEvent(display, &event);
1431
1432       switch(event.type)
1433       {
1434         case ButtonPress:
1435         case ButtonRelease:
1436         case MotionNotify:
1437         {
1438           int choice;
1439
1440           if (event.type == MotionNotify)
1441           {
1442             motion_status = TRUE;
1443             mx = ((XMotionEvent *) &event)->x;
1444             my = ((XMotionEvent *) &event)->y;
1445           }
1446           else
1447           {
1448             motion_status = FALSE;
1449             mx = ((XButtonEvent *) &event)->x;
1450             my = ((XButtonEvent *) &event)->y;
1451             if (event.type==ButtonPress)
1452               button_status = ((XButtonEvent *) &event)->button;
1453             else
1454               button_status = MB_RELEASED;
1455           }
1456
1457           if (req_state & REQ_ASK)
1458             choice = CheckYesNoButtons(mx,my,button_status);
1459           else if (req_state & REQ_CONFIRM)
1460             choice = CheckConfirmButton(mx,my,button_status);
1461           else
1462             choice = CheckPlayerButtons(mx,my,button_status);
1463
1464           switch(choice)
1465           {
1466             case BUTTON_OK:
1467               result = TRUE;
1468               break;
1469             case BUTTON_NO:
1470               result = FALSE;
1471               break;
1472             case BUTTON_CONFIRM:
1473               result = TRUE | FALSE;
1474               break;
1475
1476             case BUTTON_PLAYER_1:
1477               result = 1;
1478               break;
1479             case BUTTON_PLAYER_2:
1480               result = 2;
1481               break;
1482             case BUTTON_PLAYER_3:
1483               result = 3;
1484               break;
1485             case BUTTON_PLAYER_4:
1486               result = 4;
1487               break;
1488
1489             default:
1490               break;
1491           }
1492           break;
1493         }
1494
1495         case KeyPress:
1496           switch(XLookupKeysym((XKeyEvent *)&event,
1497                                ((XKeyEvent *)&event)->state))
1498           {
1499             case XK_Return:
1500               result = 1;
1501               break;
1502
1503             case XK_Escape:
1504               result = 0;
1505               break;
1506
1507             default:
1508               break;
1509           }
1510           if (req_state & REQ_PLAYER)
1511             result = 0;
1512           break;
1513
1514         case KeyRelease:
1515           key_joystick_mapping = 0;
1516           break;
1517
1518         default:
1519           HandleOtherEvents(&event);
1520           break;
1521       }
1522     }
1523     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1524     {
1525       int joy = AnyJoystick();
1526
1527       if (joy & JOY_BUTTON_1)
1528         result = 1;
1529       else if (joy & JOY_BUTTON_2)
1530         result = 0;
1531     }
1532
1533     DoAnimation();
1534
1535     /* don't eat all CPU time */
1536     Delay(10);
1537   }
1538
1539   if (game_status != MAINMENU)
1540     StopAnimation();
1541
1542   if (!(req_state & REQ_STAY_OPEN))
1543   {
1544     CloseDoor(DOOR_CLOSE_1);
1545
1546     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1547     {
1548       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1549                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1550                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1551       OpenDoor(DOOR_OPEN_1);
1552     }
1553   }
1554
1555 #ifndef MSDOS
1556   /* continue network game after request */
1557   if (options.network &&
1558       game_status == PLAYING &&
1559       req_state & REQUEST_WAIT_FOR)
1560     SendToServer_ContinuePlaying();
1561 #endif
1562
1563   return(result);
1564 }
1565
1566 unsigned int OpenDoor(unsigned int door_state)
1567 {
1568   unsigned int new_door_state;
1569
1570   if (door_state & DOOR_COPY_BACK)
1571   {
1572     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1573               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1574               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1575     door_state &= ~DOOR_COPY_BACK;
1576   }
1577
1578   new_door_state = MoveDoor(door_state);
1579
1580   return(new_door_state);
1581 }
1582
1583 unsigned int CloseDoor(unsigned int door_state)
1584 {
1585   unsigned int new_door_state;
1586
1587   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1588             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1589   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1590             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1591
1592   new_door_state = MoveDoor(door_state);
1593
1594   return(new_door_state);
1595 }
1596
1597 unsigned int GetDoorState()
1598 {
1599   return(MoveDoor(DOOR_GET_STATE));
1600 }
1601
1602 unsigned int MoveDoor(unsigned int door_state)
1603 {
1604   static int door1 = DOOR_OPEN_1;
1605   static int door2 = DOOR_CLOSE_2;
1606   static unsigned long door_delay = 0;
1607   int x, start, stepsize = 2;
1608   unsigned long door_delay_value = stepsize * 5;
1609
1610   if (door_state == DOOR_GET_STATE)
1611     return(door1 | door2);
1612
1613   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1614     door_state &= ~DOOR_OPEN_1;
1615   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1616     door_state &= ~DOOR_CLOSE_1;
1617   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1618     door_state &= ~DOOR_OPEN_2;
1619   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1620     door_state &= ~DOOR_CLOSE_2;
1621
1622   if (setup.quick_doors)
1623   {
1624     stepsize = 20;
1625     door_delay_value = 0;
1626     StopSound(SND_OEFFNEN);
1627   }
1628
1629   if (door_state & DOOR_ACTION)
1630   {
1631     if (!(door_state & DOOR_NO_DELAY))
1632       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1633
1634     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1635
1636     for(x=start; x<=DXSIZE; x+=stepsize)
1637     {
1638       WaitUntilDelayReached(&door_delay, door_delay_value);
1639
1640       if (door_state & DOOR_ACTION_1)
1641       {
1642         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1643         int j = (DXSIZE - i) / 3;
1644
1645         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1646                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1647                   DXSIZE,DYSIZE - i/2, DX, DY);
1648
1649         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1650
1651         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1652                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1653         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1654                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1655         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1656                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1657                   DY + 140 + j);
1658         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1659                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1660         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1661                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1662         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1663                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1664
1665         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1666                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1667                   DX, DY + 77 - j);
1668         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1669                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1670                   DX, DY + 203 - j);
1671         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1672                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1673         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1674                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1675                   DX + DXSIZE - i, DY + 77 + j);
1676         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1677                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1678                   DX + DXSIZE - i, DY + 203 + j);
1679
1680         redraw_mask |= REDRAW_DOOR_1;
1681       }
1682
1683       if (door_state & DOOR_ACTION_2)
1684       {
1685         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1686         int j = (VXSIZE - i) / 3;
1687
1688         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1689                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1690                   VXSIZE, VYSIZE - i/2, VX, VY);
1691
1692         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1693
1694         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1695                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1696         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1697                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1698         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1699                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1700         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1701                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1702
1703         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1704                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1705                   VX, VY + VYSIZE / 2 - j);
1706         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1707                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1708         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1709                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1710                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1711
1712         redraw_mask |= REDRAW_DOOR_2;
1713       }
1714
1715       BackToFront();
1716
1717       if (game_status == MAINMENU)
1718         DoAnimation();
1719     }
1720   }
1721
1722   if (setup.quick_doors)
1723     StopSound(SND_OEFFNEN);
1724
1725   if (door_state & DOOR_ACTION_1)
1726     door1 = door_state & DOOR_ACTION_1;
1727   if (door_state & DOOR_ACTION_2)
1728     door2 = door_state & DOOR_ACTION_2;
1729
1730   return(door1 | door2);
1731 }
1732
1733 int ReadPixel(Drawable d, int x, int y)
1734 {
1735   static XImage *pixelimage;
1736
1737   pixelimage = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1738   return(XGetPixel(pixelimage, 0, 0));
1739 }
1740
1741 int el2gfx(int element)
1742 {
1743   switch(element)
1744   {
1745     case EL_LEERRAUM:           return -1;
1746     case EL_ERDREICH:           return GFX_ERDREICH;
1747     case EL_MAUERWERK:          return GFX_MAUERWERK;
1748     case EL_FELSBODEN:          return GFX_FELSBODEN;
1749     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1750     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1751     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1752     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1753     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1754     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1755     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1756     case EL_SPIELER1:           return GFX_SPIELER1;
1757     case EL_SPIELER2:           return GFX_SPIELER2;
1758     case EL_SPIELER3:           return GFX_SPIELER3;
1759     case EL_SPIELER4:           return GFX_SPIELER4;
1760     case EL_KAEFER:             return GFX_KAEFER;
1761     case EL_KAEFER_R:           return GFX_KAEFER_R;
1762     case EL_KAEFER_O:           return GFX_KAEFER_O;
1763     case EL_KAEFER_L:           return GFX_KAEFER_L;
1764     case EL_KAEFER_U:           return GFX_KAEFER_U;
1765     case EL_FLIEGER:            return GFX_FLIEGER;
1766     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1767     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1768     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1769     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1770     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1771     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1772     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1773     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1774     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1775     case EL_FIREFLY:            return GFX_FIREFLY;
1776     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1777     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1778     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1779     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1780     case EL_MAMPFER:            return GFX_MAMPFER;
1781     case EL_ROBOT:              return GFX_ROBOT;
1782     case EL_BETON:              return GFX_BETON;
1783     case EL_DIAMANT:            return GFX_DIAMANT;
1784     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1785     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1786     case EL_TROPFEN:            return GFX_TROPFEN;
1787     case EL_BOMBE:              return GFX_BOMBE;
1788     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1789     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1790     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1791     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1792     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1793     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1794     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1795     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1796     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1797     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1798     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1799     case EL_LIFE:               return GFX_LIFE;
1800     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1801     case EL_DYNAMIT:            return GFX_DYNAMIT;
1802     case EL_BADEWANNE:          return GFX_BADEWANNE;
1803     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1804     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1805     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
1806     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
1807     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
1808     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
1809     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
1810     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
1811     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
1812     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
1813     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
1814     case EL_PFORTE1:            return GFX_PFORTE1;
1815     case EL_PFORTE2:            return GFX_PFORTE2;
1816     case EL_PFORTE3:            return GFX_PFORTE3;
1817     case EL_PFORTE4:            return GFX_PFORTE4;
1818     case EL_PFORTE1X:           return GFX_PFORTE1X;
1819     case EL_PFORTE2X:           return GFX_PFORTE2X;
1820     case EL_PFORTE3X:           return GFX_PFORTE3X;
1821     case EL_PFORTE4X:           return GFX_PFORTE4X;
1822     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
1823     case EL_PACMAN:             return GFX_PACMAN;
1824     case EL_PACMAN_R:           return GFX_PACMAN_R;
1825     case EL_PACMAN_O:           return GFX_PACMAN_O;
1826     case EL_PACMAN_L:           return GFX_PACMAN_L;
1827     case EL_PACMAN_U:           return GFX_PACMAN_U;
1828     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
1829     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
1830     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
1831     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
1832     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
1833     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
1834     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
1835     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
1836     case EL_MAUER_X:            return GFX_MAUER_X;
1837     case EL_MAUER_Y:            return GFX_MAUER_Y;
1838     case EL_MAUER_XY:           return GFX_MAUER_XY;
1839     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
1840     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
1841     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
1842     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
1843     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
1844     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
1845     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
1846     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
1847     case EL_MAMPFER2:           return GFX_MAMPFER2;
1848     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
1849     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
1850     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
1851     case EL_DYNABOMB:           return GFX_DYNABOMB;
1852     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
1853     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
1854     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
1855     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
1856     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
1857     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
1858     case EL_MAULWURF:           return GFX_MAULWURF;
1859     case EL_PINGUIN:            return GFX_PINGUIN;
1860     case EL_SCHWEIN:            return GFX_SCHWEIN;
1861     case EL_DRACHE:             return GFX_DRACHE;
1862     case EL_SONDE:              return GFX_SONDE;
1863     case EL_PFEIL_L:            return GFX_PFEIL_L;
1864     case EL_PFEIL_R:            return GFX_PFEIL_R;
1865     case EL_PFEIL_O:            return GFX_PFEIL_O;
1866     case EL_PFEIL_U:            return GFX_PFEIL_U;
1867     default:
1868     {
1869       if (IS_CHAR(element))
1870         return GFX_CHAR_START + (element - EL_CHAR_START);
1871       else
1872         return -1;
1873     }
1874   }
1875 }