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