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