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