rnd-19981020-2
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #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     if (XPending(display))
1387     {
1388       XEvent event;
1389
1390       XNextEvent(display, &event);
1391       switch(event.type)
1392       {
1393         case Expose:
1394           HandleExposeEvent((XExposeEvent *) &event);
1395           break;
1396         case UnmapNotify:
1397           SleepWhileUnmapped();
1398           break;
1399         case ButtonPress:
1400         case ButtonRelease:
1401         case MotionNotify:
1402         {
1403           int choice;
1404
1405           if (event.type == MotionNotify)
1406           {
1407             motion_status = TRUE;
1408             mx = ((XMotionEvent *) &event)->x;
1409             my = ((XMotionEvent *) &event)->y;
1410           }
1411           else
1412           {
1413             motion_status = FALSE;
1414             mx = ((XButtonEvent *) &event)->x;
1415             my = ((XButtonEvent *) &event)->y;
1416             if (event.type==ButtonPress)
1417               button_status = ((XButtonEvent *) &event)->button;
1418             else
1419               button_status = MB_RELEASED;
1420           }
1421
1422           if (req_state & REQ_ASK)
1423             choice = CheckYesNoButtons(mx,my,button_status);
1424           else if (req_state & REQ_CONFIRM)
1425             choice = CheckConfirmButton(mx,my,button_status);
1426           else
1427             choice = CheckPlayerButtons(mx,my,button_status);
1428
1429           switch(choice)
1430           {
1431             case BUTTON_OK:
1432               result = TRUE;
1433               break;
1434             case BUTTON_NO:
1435               result = FALSE;
1436               break;
1437             case BUTTON_CONFIRM:
1438               result = TRUE | FALSE;
1439               break;
1440             case BUTTON_PLAYER_1:
1441               result = 1;
1442               break;
1443             case BUTTON_PLAYER_2:
1444               result = 2;
1445               break;
1446             case BUTTON_PLAYER_3:
1447               result = 3;
1448               break;
1449             case BUTTON_PLAYER_4:
1450               result = 4;
1451               break;
1452             default:
1453               break;
1454           }
1455           break;
1456         }
1457         case KeyPress:
1458           switch(XLookupKeysym((XKeyEvent *)&event,
1459                                ((XKeyEvent *)&event)->state))
1460           {
1461             case XK_Return:
1462               result = 1;
1463               break;
1464             case XK_Escape:
1465               result = 0;
1466               break;
1467           }
1468           if (req_state & REQ_PLAYER)
1469             result = 0;
1470           break;
1471         case KeyRelease:
1472           key_joystick_mapping = 0;
1473           break;
1474         case FocusIn:
1475         case FocusOut:
1476           HandleFocusEvent((XFocusChangeEvent *) &event);
1477           break;
1478         case ClientMessage:
1479           HandleClientMessageEvent((XClientMessageEvent *) &event);
1480           break;
1481         default:
1482           break;
1483       }
1484     }
1485     else if (JoystickButton() == JOY_BUTTON_NEW_PRESSED)
1486     {
1487       int joy=Joystick();
1488
1489       if (joy & JOY_BUTTON_1)
1490         result = 1;
1491       else if (joy & JOY_BUTTON_2)
1492         result = 0;
1493     }
1494
1495     DoAnimation();
1496
1497     /* don't eat all CPU time */
1498     Delay(10);
1499   }
1500
1501   if (game_status != MAINMENU)
1502     StopAnimation();
1503
1504   if (!(req_state & REQ_STAY_OPEN))
1505   {
1506     CloseDoor(DOOR_CLOSE_1);
1507
1508     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1509     {
1510       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1511                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1512                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1513       OpenDoor(DOOR_OPEN_1);
1514     }
1515   }
1516
1517   /* continue network game after request */
1518   if (options.network &&
1519       game_status == PLAYING &&
1520       req_state & REQUEST_WAIT_FOR)
1521     SendToServer_ContinuePlaying();
1522
1523   return(result);
1524 }
1525
1526 unsigned int OpenDoor(unsigned int door_state)
1527 {
1528   unsigned int new_door_state;
1529
1530   if (door_state & DOOR_COPY_BACK)
1531   {
1532     XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1533               DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE+VYSIZE,
1534               DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1535     door_state &= ~DOOR_COPY_BACK;
1536   }
1537
1538   new_door_state = MoveDoor(door_state);
1539
1540   return(new_door_state);
1541 }
1542
1543 unsigned int CloseDoor(unsigned int door_state)
1544 {
1545   unsigned int new_door_state;
1546
1547   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1548             DX,DY, DXSIZE,DYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1549   XCopyArea(display,backbuffer,pix[PIX_DB_DOOR],gc,
1550             VX,VY, VXSIZE,VYSIZE, DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2);
1551
1552   new_door_state = MoveDoor(door_state);
1553
1554   return(new_door_state);
1555 }
1556
1557 unsigned int GetDoorState()
1558 {
1559   return(MoveDoor(DOOR_GET_STATE));
1560 }
1561
1562 unsigned int MoveDoor(unsigned int door_state)
1563 {
1564   static unsigned int door1 = DOOR_OPEN_1;
1565   static unsigned int door2 = DOOR_CLOSE_2;
1566   static long door_delay = 0;
1567   int x, start, stepsize = 2;
1568   long door_delay_value = stepsize * 5;
1569
1570   if (door_state == DOOR_GET_STATE)
1571     return(door1 | door2);
1572
1573   if (door1==DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1574     door_state &= ~DOOR_OPEN_1;
1575   else if (door1==DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1576     door_state &= ~DOOR_CLOSE_1;
1577   if (door2==DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1578     door_state &= ~DOOR_OPEN_2;
1579   else if (door2==DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1580     door_state &= ~DOOR_CLOSE_2;
1581
1582   if (setup.quick_doors)
1583   {
1584     stepsize = 20;
1585     door_delay_value = 0;
1586     StopSound(SND_OEFFNEN);
1587   }
1588
1589   if (door_state & DOOR_ACTION)
1590   {
1591     if (!(door_state & DOOR_NO_DELAY))
1592       PlaySoundStereo(SND_OEFFNEN,PSND_MAX_RIGHT);
1593
1594     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1595
1596     for(x=start; x<=DXSIZE; x+=stepsize)
1597     {
1598       WaitUntilDelayReached(&door_delay, door_delay_value);
1599
1600       if (door_state & DOOR_ACTION_1)
1601       {
1602         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1603         int j = (DXSIZE - i)/3;
1604
1605         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1606                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1+i/2,
1607                   DXSIZE,DYSIZE-i/2, DX,DY);
1608
1609         XFillRectangle(display,drawto,gc,DX,DY+DYSIZE-i/2,DXSIZE,i/2);
1610
1611         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1612                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1613         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1614                   DXSIZE,DOOR_GFX_PAGEY1, i,77, DX+DXSIZE-i,DY+j);
1615         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1616                   DXSIZE,DOOR_GFX_PAGEY1+140, i,63, DX+DXSIZE-i,DY+140+j);
1617         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1618                        DX-DXSIZE+i,DY-(DOOR_GFX_PAGEY1+j));
1619         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1620                   DXSIZE-i,DOOR_GFX_PAGEY1+j, i,77-j, DX,DY);
1621         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1622                   DXSIZE-i,DOOR_GFX_PAGEY1+140, i,63, DX,DY+140-j);
1623
1624         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1625                   DXSIZE-i,DOOR_GFX_PAGEY1+77, i,63,
1626                   DX,DY+77-j);
1627         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1628                   DXSIZE-i,DOOR_GFX_PAGEY1+203, i,77,
1629                   DX,DY+203-j);
1630         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1631                        DX-i,(DY+j)-DOOR_GFX_PAGEY1);
1632         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1633                   DXSIZE,DOOR_GFX_PAGEY1+77, i,63,
1634                   DX+DXSIZE-i,DY+77+j);
1635         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1636                   DXSIZE,DOOR_GFX_PAGEY1+203, i,77-j,
1637                   DX+DXSIZE-i,DY+203+j);
1638
1639         redraw_mask |= REDRAW_DOOR_1;
1640       }
1641
1642       if (door_state & DOOR_ACTION_2)
1643       {
1644         int i = (door_state & DOOR_OPEN_2 ? VXSIZE-x : x);
1645         int j = (VXSIZE - i)/3;
1646
1647         XCopyArea(display,pix[PIX_DB_DOOR],drawto,gc,
1648                   DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY2+i/2,
1649                   VXSIZE,VYSIZE-i/2, VX,VY);
1650
1651         XFillRectangle(display,drawto,gc,VX,VY+VYSIZE-i/2,VXSIZE,i/2);
1652
1653         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1654                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1655         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1656                   VXSIZE,DOOR_GFX_PAGEY2, i,VYSIZE/2, VX+VXSIZE-i,VY+j);
1657         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1658                        VX-VXSIZE+i,VY-(DOOR_GFX_PAGEY2+j));
1659         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1660                   VXSIZE-i,DOOR_GFX_PAGEY2+j, i,VYSIZE/2-j, VX,VY);
1661
1662         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1663                   VXSIZE-i,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2,
1664                   VX,VY+VYSIZE/2-j);
1665         XSetClipOrigin(display,clip_gc[PIX_DOOR],
1666                        VX-i,(VY+j)-DOOR_GFX_PAGEY2);
1667         XCopyArea(display,pix[PIX_DOOR],drawto,clip_gc[PIX_DOOR],
1668                   VXSIZE,DOOR_GFX_PAGEY2+VYSIZE/2, i,VYSIZE/2-j,
1669                   VX+VXSIZE-i,VY+VYSIZE/2+j);
1670
1671         redraw_mask |= REDRAW_DOOR_2;
1672       }
1673
1674       BackToFront();
1675
1676       if (game_status == MAINMENU)
1677         DoAnimation();
1678     }
1679   }
1680
1681   if (setup.quick_doors)
1682     StopSound(SND_OEFFNEN);
1683
1684   if (door_state & DOOR_ACTION_1)
1685     door1 = door_state & DOOR_ACTION_1;
1686   if (door_state & DOOR_ACTION_2)
1687     door2 = door_state & DOOR_ACTION_2;
1688
1689   return(door1 | door2);
1690 }
1691
1692 int ReadPixel(Drawable d, int x, int y)
1693 {
1694   static XImage *pixelimage;
1695
1696   pixelimage = XGetImage(display, d, x,y, 1,1, AllPlanes, ZPixmap);
1697   return(XGetPixel(pixelimage,0,0));
1698 }
1699
1700 int el2gfx(int element)
1701 {
1702   switch(element)
1703   {
1704     case EL_LEERRAUM:           return(-1);
1705     case EL_ERDREICH:           return(GFX_ERDREICH);
1706     case EL_MAUERWERK:          return(GFX_MAUERWERK);
1707     case EL_FELSBODEN:          return(GFX_FELSBODEN);
1708     case EL_FELSBROCKEN:        return(GFX_FELSBROCKEN);
1709     case EL_SCHLUESSEL:         return(GFX_SCHLUESSEL);
1710     case EL_EDELSTEIN:          return(GFX_EDELSTEIN);
1711     case EL_AUSGANG_ZU:         return(GFX_AUSGANG_ZU);
1712     case EL_AUSGANG_ACT:        return(GFX_AUSGANG_ACT);
1713     case EL_AUSGANG_AUF:        return(GFX_AUSGANG_AUF);
1714     case EL_SPIELFIGUR:         return(GFX_SPIELFIGUR);
1715     case EL_SPIELER1:           return(GFX_SPIELER1);
1716     case EL_SPIELER2:           return(GFX_SPIELER2);
1717     case EL_SPIELER3:           return(GFX_SPIELER3);
1718     case EL_SPIELER4:           return(GFX_SPIELER4);
1719     case EL_KAEFER:             return(GFX_KAEFER);
1720     case EL_KAEFER_R:           return(GFX_KAEFER_R);
1721     case EL_KAEFER_O:           return(GFX_KAEFER_O);
1722     case EL_KAEFER_L:           return(GFX_KAEFER_L);
1723     case EL_KAEFER_U:           return(GFX_KAEFER_U);
1724     case EL_FLIEGER:            return(GFX_FLIEGER);
1725     case EL_FLIEGER_R:          return(GFX_FLIEGER_R);
1726     case EL_FLIEGER_O:          return(GFX_FLIEGER_O);
1727     case EL_FLIEGER_L:          return(GFX_FLIEGER_L);
1728     case EL_FLIEGER_U:          return(GFX_FLIEGER_U);
1729     case EL_BUTTERFLY:          return(GFX_BUTTERFLY);
1730     case EL_BUTTERFLY_R:        return(GFX_BUTTERFLY_R);
1731     case EL_BUTTERFLY_O:        return(GFX_BUTTERFLY_O);
1732     case EL_BUTTERFLY_L:        return(GFX_BUTTERFLY_L);
1733     case EL_BUTTERFLY_U:        return(GFX_BUTTERFLY_U);
1734     case EL_FIREFLY:            return(GFX_FIREFLY);
1735     case EL_FIREFLY_R:          return(GFX_FIREFLY_R);
1736     case EL_FIREFLY_O:          return(GFX_FIREFLY_O);
1737     case EL_FIREFLY_L:          return(GFX_FIREFLY_L);
1738     case EL_FIREFLY_U:          return(GFX_FIREFLY_U);
1739     case EL_MAMPFER:            return(GFX_MAMPFER);
1740     case EL_ROBOT:              return(GFX_ROBOT);
1741     case EL_BETON:              return(GFX_BETON);
1742     case EL_DIAMANT:            return(GFX_DIAMANT);
1743     case EL_MORAST_LEER:        return(GFX_MORAST_LEER);
1744     case EL_MORAST_VOLL:        return(GFX_MORAST_VOLL);
1745     case EL_TROPFEN:            return(GFX_TROPFEN);
1746     case EL_BOMBE:              return(GFX_BOMBE);
1747     case EL_SIEB_LEER:          return(GFX_SIEB_LEER);
1748     case EL_SIEB_VOLL:          return(GFX_SIEB_VOLL);
1749     case EL_SIEB_TOT:           return(GFX_SIEB_TOT);
1750     case EL_SALZSAEURE:         return(GFX_SALZSAEURE);
1751     case EL_AMOEBE_TOT:         return(GFX_AMOEBE_TOT);
1752     case EL_AMOEBE_NASS:        return(GFX_AMOEBE_NASS);
1753     case EL_AMOEBE_NORM:        return(GFX_AMOEBE_NORM);
1754     case EL_AMOEBE_VOLL:        return(GFX_AMOEBE_VOLL);
1755     case EL_AMOEBE_BD:          return(GFX_AMOEBE_BD);
1756     case EL_AMOEBA2DIAM:        return(GFX_AMOEBA2DIAM);
1757     case EL_KOKOSNUSS:          return(GFX_KOKOSNUSS);
1758     case EL_LIFE:               return(GFX_LIFE);
1759     case EL_LIFE_ASYNC:         return(GFX_LIFE_ASYNC);
1760     case EL_DYNAMIT:            return(GFX_DYNAMIT);
1761     case EL_BADEWANNE:          return(GFX_BADEWANNE);
1762     case EL_BADEWANNE1:         return(GFX_BADEWANNE1);
1763     case EL_BADEWANNE2:         return(GFX_BADEWANNE2);
1764     case EL_BADEWANNE3:         return(GFX_BADEWANNE3);
1765     case EL_BADEWANNE4:         return(GFX_BADEWANNE4);
1766     case EL_BADEWANNE5:         return(GFX_BADEWANNE5);
1767     case EL_ABLENK_AUS:         return(GFX_ABLENK_AUS);
1768     case EL_ABLENK_EIN:         return(GFX_ABLENK_EIN);
1769     case EL_SCHLUESSEL1:        return(GFX_SCHLUESSEL1);
1770     case EL_SCHLUESSEL2:        return(GFX_SCHLUESSEL2);
1771     case EL_SCHLUESSEL3:        return(GFX_SCHLUESSEL3);
1772     case EL_SCHLUESSEL4:        return(GFX_SCHLUESSEL4);
1773     case EL_PFORTE1:            return(GFX_PFORTE1);
1774     case EL_PFORTE2:            return(GFX_PFORTE2);
1775     case EL_PFORTE3:            return(GFX_PFORTE3);
1776     case EL_PFORTE4:            return(GFX_PFORTE4);
1777     case EL_PFORTE1X:           return(GFX_PFORTE1X);
1778     case EL_PFORTE2X:           return(GFX_PFORTE2X);
1779     case EL_PFORTE3X:           return(GFX_PFORTE3X);
1780     case EL_PFORTE4X:           return(GFX_PFORTE4X);
1781     case EL_DYNAMIT_AUS:        return(GFX_DYNAMIT_AUS);
1782     case EL_PACMAN:             return(GFX_PACMAN);
1783     case EL_PACMAN_R:           return(GFX_PACMAN_R);
1784     case EL_PACMAN_O:           return(GFX_PACMAN_O);
1785     case EL_PACMAN_L:           return(GFX_PACMAN_L);
1786     case EL_PACMAN_U:           return(GFX_PACMAN_U);
1787     case EL_UNSICHTBAR:         return(GFX_UNSICHTBAR);
1788     case EL_ERZ_EDEL:           return(GFX_ERZ_EDEL);
1789     case EL_ERZ_DIAM:           return(GFX_ERZ_DIAM);
1790     case EL_BIRNE_AUS:          return(GFX_BIRNE_AUS);
1791     case EL_BIRNE_EIN:          return(GFX_BIRNE_EIN);
1792     case EL_ZEIT_VOLL:          return(GFX_ZEIT_VOLL);
1793     case EL_ZEIT_LEER:          return(GFX_ZEIT_LEER);
1794     case EL_MAUER_LEBT:         return(GFX_MAUER_LEBT);
1795     case EL_MAUER_X:            return(GFX_MAUER_X);
1796     case EL_MAUER_Y:            return(GFX_MAUER_Y);
1797     case EL_MAUER_XY:           return(GFX_MAUER_XY);
1798     case EL_EDELSTEIN_BD:       return(GFX_EDELSTEIN_BD);
1799     case EL_EDELSTEIN_GELB:     return(GFX_EDELSTEIN_GELB);
1800     case EL_EDELSTEIN_ROT:      return(GFX_EDELSTEIN_ROT);
1801     case EL_EDELSTEIN_LILA:     return(GFX_EDELSTEIN_LILA);
1802     case EL_ERZ_EDEL_BD:        return(GFX_ERZ_EDEL_BD);
1803     case EL_ERZ_EDEL_GELB:      return(GFX_ERZ_EDEL_GELB);
1804     case EL_ERZ_EDEL_ROT:       return(GFX_ERZ_EDEL_ROT);
1805     case EL_ERZ_EDEL_LILA:      return(GFX_ERZ_EDEL_LILA);
1806     case EL_MAMPFER2:           return(GFX_MAMPFER2);
1807     case EL_SIEB2_LEER:         return(GFX_SIEB2_LEER);
1808     case EL_SIEB2_VOLL:         return(GFX_SIEB2_VOLL);
1809     case EL_SIEB2_TOT:          return(GFX_SIEB2_TOT);
1810     case EL_DYNABOMB:           return(GFX_DYNABOMB);
1811     case EL_DYNABOMB_NR:        return(GFX_DYNABOMB_NR);
1812     case EL_DYNABOMB_SZ:        return(GFX_DYNABOMB_SZ);
1813     case EL_DYNABOMB_XL:        return(GFX_DYNABOMB_XL);
1814     case EL_SOKOBAN_OBJEKT:     return(GFX_SOKOBAN_OBJEKT);
1815     case EL_SOKOBAN_FELD_LEER:  return(GFX_SOKOBAN_FELD_LEER);
1816     case EL_SOKOBAN_FELD_VOLL:  return(GFX_SOKOBAN_FELD_VOLL);
1817     case EL_MAULWURF:           return(GFX_MAULWURF);
1818     case EL_PINGUIN:            return(GFX_PINGUIN);
1819     case EL_SCHWEIN:            return(GFX_SCHWEIN);
1820     case EL_DRACHE:             return(GFX_DRACHE);
1821     case EL_SONDE:              return(GFX_SONDE);
1822     case EL_PFEIL_L:            return(GFX_PFEIL_L);
1823     case EL_PFEIL_R:            return(GFX_PFEIL_R);
1824     case EL_PFEIL_O:            return(GFX_PFEIL_O);
1825     case EL_PFEIL_U:            return(GFX_PFEIL_U);
1826     default:
1827     {
1828       if (IS_CHAR(element))
1829         return(GFX_CHAR_START + (element-EL_CHAR_START));
1830       else
1831         return(-1);
1832     }
1833   }
1834 }