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