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