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