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