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