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