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