rnd-19981227-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     if (element != EL_SP_INFOTRON)
975       graphic += phase * (element == EL_FELSBROCKEN ? 2 : 1);
976   }
977   else if ((element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
978             element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL) && SiebAktiv)
979   {
980     graphic += 3 - (SiebAktiv % 8) / 2;
981   }
982   else if (IS_AMOEBOID(element))
983   {
984     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
985     graphic += (x + 2 * y + 4) % 4;
986   }
987   else if (element == EL_MAUER_LEBT)
988   {
989     boolean links_massiv = FALSE, rechts_massiv = FALSE;
990
991     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
992       links_massiv = TRUE;
993     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
994       rechts_massiv = TRUE;
995
996     if (links_massiv && rechts_massiv)
997       graphic = GFX_MAUERWERK;
998     else if (links_massiv)
999       graphic = GFX_MAUER_R;
1000     else if (rechts_massiv)
1001       graphic = GFX_MAUER_L;
1002   }
1003
1004   if (dx || dy)
1005     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1006   else if (mask_mode == USE_MASKING)
1007     DrawGraphicThruMask(x, y, graphic);
1008   else
1009     DrawGraphic(x, y, graphic);
1010 }
1011
1012 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1013                          int cut_mode, int mask_mode)
1014 {
1015   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1016     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1017                          cut_mode, mask_mode);
1018 }
1019
1020 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1021                               int cut_mode)
1022 {
1023   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1024 }
1025
1026 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1027                              int cut_mode)
1028 {
1029   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1030 }
1031
1032 void DrawScreenElementThruMask(int x, int y, int element)
1033 {
1034   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1035 }
1036
1037 void DrawLevelElementThruMask(int x, int y, int element)
1038 {
1039   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1040 }
1041
1042 void DrawLevelFieldThruMask(int x, int y)
1043 {
1044   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1045 }
1046
1047 void ErdreichAnbroeckeln(int x, int y)
1048 {
1049   int i, width, height, cx,cy;
1050   int ux = LEVELX(x), uy = LEVELY(y);
1051   int element, graphic;
1052   int snip = 4;
1053   static int xy[4][2] =
1054   {
1055     { 0, -1 },
1056     { -1, 0 },
1057     { +1, 0 },
1058     { 0, +1 }
1059   };
1060
1061   if (!IN_LEV_FIELD(ux, uy))
1062     return;
1063
1064   element = Feld[ux][uy];
1065
1066   if (element == EL_ERDREICH)
1067   {
1068     if (!IN_SCR_FIELD(x, y))
1069       return;
1070
1071     graphic = GFX_ERDENRAND;
1072
1073     for(i=0; i<4; i++)
1074     {
1075       int uxx, uyy;
1076
1077       uxx = ux + xy[i][0];
1078       uyy = uy + xy[i][1];
1079       if (!IN_LEV_FIELD(uxx, uyy))
1080         element = EL_BETON;
1081       else
1082         element = Feld[uxx][uyy];
1083
1084       if (element == EL_ERDREICH)
1085         continue;
1086
1087       if (i == 1 || i == 2)
1088       {
1089         width = snip;
1090         height = TILEY;
1091         cx = (i == 2 ? TILEX - snip : 0);
1092         cy = 0;
1093       }
1094       else
1095       {
1096         width = TILEX;
1097         height = snip;
1098         cx = 0;
1099         cy = (i == 3 ? TILEY - snip : 0);
1100       }
1101
1102       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1103                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1104                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1105                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1106     }
1107
1108     MarkTileDirty(x, y);
1109   }
1110   else
1111   {
1112     graphic = GFX_ERDENRAND;
1113
1114     for(i=0; i<4; i++)
1115     {
1116       int xx, yy, uxx, uyy;
1117
1118       xx = x + xy[i][0];
1119       yy = y + xy[i][1];
1120       uxx = ux + xy[i][0];
1121       uyy = uy + xy[i][1];
1122
1123       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1124           !IN_SCR_FIELD(xx, yy))
1125         continue;
1126
1127       if (i == 1 || i == 2)
1128       {
1129         width = snip;
1130         height = TILEY;
1131         cx = (i == 1 ? TILEX - snip : 0);
1132         cy = 0;
1133       }
1134       else
1135       {
1136         width = TILEX;
1137         height = snip;
1138         cx = 0;
1139         cy = (i==0 ? TILEY-snip : 0);
1140       }
1141
1142       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1143                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1144                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1145                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1146
1147       MarkTileDirty(xx, yy);
1148     }
1149   }
1150 }
1151
1152 void DrawScreenElement(int x, int y, int element)
1153 {
1154   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1155   ErdreichAnbroeckeln(x, y);
1156 }
1157
1158 void DrawLevelElement(int x, int y, int element)
1159 {
1160   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1161     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1162 }
1163
1164 void DrawScreenField(int x, int y)
1165 {
1166   int ux = LEVELX(x), uy = LEVELY(y);
1167   int element;
1168
1169   if (!IN_LEV_FIELD(ux, uy))
1170   {
1171     DrawScreenElement(x, y, EL_BETON);
1172     return;
1173   }
1174
1175   element = Feld[ux][uy];
1176
1177   if (IS_MOVING(ux, uy))
1178   {
1179     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1180     boolean cut_mode = NO_CUTTING;
1181
1182     if (Store[ux][uy] == EL_MORAST_LEER ||
1183         Store[ux][uy] == EL_SIEB_LEER ||
1184         Store[ux][uy] == EL_SIEB2_LEER ||
1185         Store[ux][uy] == EL_AMOEBE_NASS)
1186       cut_mode = CUT_ABOVE;
1187     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1188              Store[ux][uy] == EL_SIEB_VOLL ||
1189              Store[ux][uy] == EL_SIEB2_VOLL)
1190       cut_mode = CUT_BELOW;
1191
1192     if (cut_mode == CUT_ABOVE)
1193       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1194     else
1195       DrawScreenElement(x, y, EL_LEERRAUM);
1196
1197     if (horiz_move)
1198       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1199     else
1200       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1201
1202     if (Store[ux][uy] == EL_SALZSAEURE)
1203       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1204   }
1205   else if (IS_BLOCKED(ux, uy))
1206   {
1207     int oldx, oldy;
1208     int sx, sy;
1209     int horiz_move;
1210     boolean cut_mode = NO_CUTTING;
1211
1212     Blocked2Moving(ux, uy, &oldx, &oldy);
1213     sx = SCREENX(oldx);
1214     sy = SCREENY(oldy);
1215     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1216                   MovDir[oldx][oldy] == MV_RIGHT);
1217
1218     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1219         Store[oldx][oldy] == EL_SIEB_LEER ||
1220         Store[oldx][oldy] == EL_SIEB2_LEER ||
1221         Store[oldx][oldy] == EL_AMOEBE_NASS)
1222       cut_mode = CUT_ABOVE;
1223
1224     DrawScreenElement(x, y, EL_LEERRAUM);
1225     element = Feld[oldx][oldy];
1226
1227     if (horiz_move)
1228       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1229     else
1230       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1231   }
1232   else if (IS_DRAWABLE(element))
1233     DrawScreenElement(x, y, element);
1234   else
1235     DrawScreenElement(x, y, EL_LEERRAUM);
1236 }
1237
1238 void DrawLevelField(int x, int y)
1239 {
1240   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1241     DrawScreenField(SCREENX(x), SCREENY(y));
1242   else if (IS_MOVING(x, y))
1243   {
1244     int newx,newy;
1245
1246     Moving2Blocked(x, y, &newx, &newy);
1247     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1248       DrawScreenField(SCREENX(newx), SCREENY(newy));
1249   }
1250   else if (IS_BLOCKED(x, y))
1251   {
1252     int oldx, oldy;
1253
1254     Blocked2Moving(x, y, &oldx, &oldy);
1255     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1256       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1257   }
1258 }
1259
1260 void DrawMiniElement(int x, int y, int element)
1261 {
1262   int graphic;
1263
1264   if (!element)
1265   {
1266     DrawMiniGraphic(x, y, -1);
1267     return;
1268   }
1269
1270   graphic = el2gfx(element);
1271   DrawMiniGraphic(x, y, graphic);
1272 }
1273
1274 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1275 {
1276   int x = sx + scroll_x, y = sy + scroll_y;
1277
1278   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1279     DrawMiniElement(sx, sy, EL_LEERRAUM);
1280   else if (x == -1 || x == lev_fieldx || y == -1 || y == lev_fieldy)
1281     DrawMiniElement(sx, sy, EL_BETON);
1282   else
1283     DrawMiniElement(sx, sy, Feld[x][y]);
1284 }
1285
1286 void DrawMicroElement(int xpos, int ypos, int element)
1287 {
1288   int graphic;
1289
1290   if (element == EL_LEERRAUM)
1291     return;
1292
1293   graphic = el2gfx(element);
1294
1295   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1296   {
1297     graphic -= GFX_START_ROCKSMORE;
1298     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1299               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1300               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1301               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1302   }
1303   else
1304     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1305               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1306               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1307               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1308 }
1309
1310 void DrawLevel()
1311 {
1312   int x,y;
1313
1314   ClearWindow();
1315
1316   for(x=BX1; x<=BX2; x++)
1317     for(y=BY1; y<=BY2; y++)
1318       DrawScreenField(x, y);
1319
1320   if (setup.soft_scrolling)
1321     XCopyArea(display, fieldbuffer, backbuffer, gc,
1322               FX, FY, SXSIZE, SYSIZE, SX, SY);
1323
1324   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1325 }
1326
1327 void DrawMiniLevel(int scroll_x, int scroll_y)
1328 {
1329   int x,y;
1330
1331   ClearWindow();
1332
1333   for(x=0; x<2*SCR_FIELDX; x++)
1334     for(y=0; y<2*SCR_FIELDY; y++)
1335       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1336
1337   redraw_mask |= REDRAW_FIELD;
1338 }
1339
1340 void DrawMicroLevel(int xpos, int ypos)
1341 {
1342   int x,y;
1343
1344   XFillRectangle(display, drawto, gc,
1345                  xpos - MICRO_TILEX, ypos - MICRO_TILEY,
1346                  MICRO_TILEX * (STD_LEV_FIELDX + 2),
1347                  MICRO_TILEY * (STD_LEV_FIELDY + 2));
1348   if (lev_fieldx < STD_LEV_FIELDX)
1349     xpos += (STD_LEV_FIELDX - lev_fieldx)/2 * MICRO_TILEX;
1350   if (lev_fieldy < STD_LEV_FIELDY)
1351     ypos += (STD_LEV_FIELDY - lev_fieldy)/2 * MICRO_TILEY;
1352
1353   for(x=-1; x<=STD_LEV_FIELDX; x++)
1354     for(y=-1; y<=STD_LEV_FIELDY; y++)
1355       if (x >= 0 && x < lev_fieldx && y >= 0 && y < lev_fieldy)
1356         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1357                          Ur[x][y]);
1358       else if (x >= -1 && x < lev_fieldx+1 && y >= -1 && y < lev_fieldy+1)
1359         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1360                          EL_BETON);
1361
1362   XFillRectangle(display, drawto,gc, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1363
1364   if (level.name)
1365   {
1366     int len = strlen(level.name);
1367     int lxpos = SX + (SXSIZE - len * FONT4_XSIZE) / 2;
1368     int lypos = MICROLABEL_YPOS;
1369
1370     DrawText(lxpos, lypos, level.name, FS_SMALL, FC_SPECIAL2);
1371   }
1372
1373   redraw_mask |= REDRAW_MICROLEV;
1374 }
1375
1376 int REQ_in_range(int x, int y)
1377 {
1378   if (y > DY+249 && y < DY+278)
1379   {
1380     if (x > DX+1 && x < DX+48)
1381       return 1;
1382     else if (x > DX+51 && x < DX+98) 
1383       return 2;
1384   }
1385   return 0;
1386 }
1387
1388 boolean Request(char *text, unsigned int req_state)
1389 {
1390   int mx, my, ty, result = -1;
1391   unsigned int old_door_state;
1392
1393 #ifndef MSDOS
1394   /* pause network game while waiting for request to answer */
1395   if (options.network &&
1396       game_status == PLAYING &&
1397       req_state & REQUEST_WAIT_FOR)
1398     SendToServer_PausePlaying();
1399 #endif
1400
1401   old_door_state = GetDoorState();
1402
1403   CloseDoor(DOOR_CLOSE_1);
1404
1405   /* Alten Türinhalt sichern */
1406   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1407             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1408             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1409
1410   /* Fragetext schreiben */
1411   XFillRectangle(display, pix[PIX_DB_DOOR], gc,
1412                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE);
1413
1414   for(ty=0; ty<13; ty++)
1415   {
1416     int tx, tl, tc;
1417     char txt[256];
1418
1419     if (!*text)
1420       break;
1421
1422     for(tl=0,tx=0; tx<7; tl++,tx++)
1423     {
1424       tc = *(text + tx);
1425       if (!tc || tc == 32)
1426         break;
1427     }
1428     if (!tl)
1429     { 
1430       text++; 
1431       ty--; 
1432       continue; 
1433     }
1434     sprintf(txt, text); 
1435     txt[tl] = 0;
1436     DrawTextExt(pix[PIX_DB_DOOR], gc,
1437                 DOOR_GFX_PAGEX1 + 51 - (tl * 14)/2, SY + ty * 16,
1438                 txt, FS_SMALL, FC_YELLOW);
1439     text += tl + (tc == 32 ? 1 : 0);
1440   }
1441
1442   if (req_state & REQ_ASK)
1443   {
1444     DrawYesNoButton(BUTTON_OK, DB_INIT);
1445     DrawYesNoButton(BUTTON_NO, DB_INIT);
1446   }
1447   else if (req_state & REQ_CONFIRM)
1448   {
1449     DrawConfirmButton(BUTTON_CONFIRM, DB_INIT);
1450   }
1451   else if (req_state & REQ_PLAYER)
1452   {
1453     DrawPlayerButton(BUTTON_PLAYER_1, DB_INIT);
1454     DrawPlayerButton(BUTTON_PLAYER_2, DB_INIT);
1455     DrawPlayerButton(BUTTON_PLAYER_3, DB_INIT);
1456     DrawPlayerButton(BUTTON_PLAYER_4, DB_INIT);
1457   }
1458
1459   OpenDoor(DOOR_OPEN_1);
1460   ClearEventQueue();
1461
1462   if (!(req_state & REQUEST_WAIT_FOR))
1463     return(FALSE);
1464
1465   if (game_status != MAINMENU)
1466     InitAnimation();
1467
1468   button_status = MB_RELEASED;
1469
1470   while(result < 0)
1471   {
1472     if (XPending(display))
1473     {
1474       XEvent event;
1475
1476       XNextEvent(display, &event);
1477
1478       switch(event.type)
1479       {
1480         case ButtonPress:
1481         case ButtonRelease:
1482         case MotionNotify:
1483         {
1484           int choice;
1485
1486           if (event.type == MotionNotify)
1487           {
1488             motion_status = TRUE;
1489             mx = ((XMotionEvent *) &event)->x;
1490             my = ((XMotionEvent *) &event)->y;
1491           }
1492           else
1493           {
1494             motion_status = FALSE;
1495             mx = ((XButtonEvent *) &event)->x;
1496             my = ((XButtonEvent *) &event)->y;
1497             if (event.type==ButtonPress)
1498               button_status = ((XButtonEvent *) &event)->button;
1499             else
1500               button_status = MB_RELEASED;
1501           }
1502
1503           if (req_state & REQ_ASK)
1504             choice = CheckYesNoButtons(mx,my,button_status);
1505           else if (req_state & REQ_CONFIRM)
1506             choice = CheckConfirmButton(mx,my,button_status);
1507           else
1508             choice = CheckPlayerButtons(mx,my,button_status);
1509
1510           switch(choice)
1511           {
1512             case BUTTON_OK:
1513               result = TRUE;
1514               break;
1515             case BUTTON_NO:
1516               result = FALSE;
1517               break;
1518             case BUTTON_CONFIRM:
1519               result = TRUE | FALSE;
1520               break;
1521
1522             case BUTTON_PLAYER_1:
1523               result = 1;
1524               break;
1525             case BUTTON_PLAYER_2:
1526               result = 2;
1527               break;
1528             case BUTTON_PLAYER_3:
1529               result = 3;
1530               break;
1531             case BUTTON_PLAYER_4:
1532               result = 4;
1533               break;
1534
1535             default:
1536               break;
1537           }
1538           break;
1539         }
1540
1541         case KeyPress:
1542           switch(XLookupKeysym((XKeyEvent *)&event,
1543                                ((XKeyEvent *)&event)->state))
1544           {
1545             case XK_Return:
1546               result = 1;
1547               break;
1548
1549             case XK_Escape:
1550               result = 0;
1551               break;
1552
1553             default:
1554               break;
1555           }
1556           if (req_state & REQ_PLAYER)
1557             result = 0;
1558           break;
1559
1560         case KeyRelease:
1561           key_joystick_mapping = 0;
1562           break;
1563
1564         default:
1565           HandleOtherEvents(&event);
1566           break;
1567       }
1568     }
1569     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1570     {
1571       int joy = AnyJoystick();
1572
1573       if (joy & JOY_BUTTON_1)
1574         result = 1;
1575       else if (joy & JOY_BUTTON_2)
1576         result = 0;
1577     }
1578
1579     DoAnimation();
1580
1581     /* don't eat all CPU time */
1582     Delay(10);
1583   }
1584
1585   if (game_status != MAINMENU)
1586     StopAnimation();
1587
1588   if (!(req_state & REQ_STAY_OPEN))
1589   {
1590     CloseDoor(DOOR_CLOSE_1);
1591
1592     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1593     {
1594       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1595                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1596                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1597       OpenDoor(DOOR_OPEN_1);
1598     }
1599   }
1600
1601 #ifndef MSDOS
1602   /* continue network game after request */
1603   if (options.network &&
1604       game_status == PLAYING &&
1605       req_state & REQUEST_WAIT_FOR)
1606     SendToServer_ContinuePlaying();
1607 #endif
1608
1609   return(result);
1610 }
1611
1612 unsigned int OpenDoor(unsigned int door_state)
1613 {
1614   unsigned int new_door_state;
1615
1616   if (door_state & DOOR_COPY_BACK)
1617   {
1618     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1619               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1620               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1621     door_state &= ~DOOR_COPY_BACK;
1622   }
1623
1624   new_door_state = MoveDoor(door_state);
1625
1626   return(new_door_state);
1627 }
1628
1629 unsigned int CloseDoor(unsigned int door_state)
1630 {
1631   unsigned int new_door_state;
1632
1633   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1634             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1635   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1636             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1637
1638   new_door_state = MoveDoor(door_state);
1639
1640   return(new_door_state);
1641 }
1642
1643 unsigned int GetDoorState()
1644 {
1645   return(MoveDoor(DOOR_GET_STATE));
1646 }
1647
1648 unsigned int MoveDoor(unsigned int door_state)
1649 {
1650   static int door1 = DOOR_OPEN_1;
1651   static int door2 = DOOR_CLOSE_2;
1652   static unsigned long door_delay = 0;
1653   int x, start, stepsize = 2;
1654   unsigned long door_delay_value = stepsize * 5;
1655
1656   if (door_state == DOOR_GET_STATE)
1657     return(door1 | door2);
1658
1659   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1660     door_state &= ~DOOR_OPEN_1;
1661   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1662     door_state &= ~DOOR_CLOSE_1;
1663   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1664     door_state &= ~DOOR_OPEN_2;
1665   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1666     door_state &= ~DOOR_CLOSE_2;
1667
1668   if (setup.quick_doors)
1669   {
1670     stepsize = 20;
1671     door_delay_value = 0;
1672     StopSound(SND_OEFFNEN);
1673   }
1674
1675   if (door_state & DOOR_ACTION)
1676   {
1677     if (!(door_state & DOOR_NO_DELAY))
1678       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1679
1680     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1681
1682     for(x=start; x<=DXSIZE; x+=stepsize)
1683     {
1684       WaitUntilDelayReached(&door_delay, door_delay_value);
1685
1686       if (door_state & DOOR_ACTION_1)
1687       {
1688         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1689         int j = (DXSIZE - i) / 3;
1690
1691         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1692                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
1693                   DXSIZE,DYSIZE - i/2, DX, DY);
1694
1695         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
1696
1697         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1698                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1699         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1700                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
1701         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1702                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
1703                   DY + 140 + j);
1704         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1705                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
1706         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1707                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
1708         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1709                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
1710
1711         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1712                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
1713                   DX, DY + 77 - j);
1714         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1715                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
1716                   DX, DY + 203 - j);
1717         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1718                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
1719         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1720                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
1721                   DX + DXSIZE - i, DY + 77 + j);
1722         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1723                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
1724                   DX + DXSIZE - i, DY + 203 + j);
1725
1726         redraw_mask |= REDRAW_DOOR_1;
1727       }
1728
1729       if (door_state & DOOR_ACTION_2)
1730       {
1731         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
1732         int j = (VXSIZE - i) / 3;
1733
1734         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
1735                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
1736                   VXSIZE, VYSIZE - i/2, VX, VY);
1737
1738         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
1739
1740         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1741                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1742         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1743                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
1744         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1745                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
1746         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
1747                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
1748
1749         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1750                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
1751                   VX, VY + VYSIZE / 2 - j);
1752         XSetClipOrigin(display, clip_gc[PIX_DOOR],
1753                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
1754         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
1755                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
1756                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
1757
1758         redraw_mask |= REDRAW_DOOR_2;
1759       }
1760
1761       BackToFront();
1762
1763       if (game_status == MAINMENU)
1764         DoAnimation();
1765     }
1766   }
1767
1768   if (setup.quick_doors)
1769     StopSound(SND_OEFFNEN);
1770
1771   if (door_state & DOOR_ACTION_1)
1772     door1 = door_state & DOOR_ACTION_1;
1773   if (door_state & DOOR_ACTION_2)
1774     door2 = door_state & DOOR_ACTION_2;
1775
1776   return(door1 | door2);
1777 }
1778
1779 int ReadPixel(Drawable d, int x, int y)
1780 {
1781   XImage *pixel_image;
1782   unsigned long pixel_value;
1783
1784   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
1785   pixel_value = XGetPixel(pixel_image, 0, 0);
1786
1787   XDestroyImage(pixel_image);
1788
1789   return pixel_value;
1790 }
1791
1792 int el2gfx(int element)
1793 {
1794   switch(element)
1795   {
1796     case EL_LEERRAUM:           return -1;
1797     case EL_ERDREICH:           return GFX_ERDREICH;
1798     case EL_MAUERWERK:          return GFX_MAUERWERK;
1799     case EL_FELSBODEN:          return GFX_FELSBODEN;
1800     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
1801     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
1802     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
1803     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
1804     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
1805     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
1806     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
1807     case EL_SPIELER1:           return GFX_SPIELER1;
1808     case EL_SPIELER2:           return GFX_SPIELER2;
1809     case EL_SPIELER3:           return GFX_SPIELER3;
1810     case EL_SPIELER4:           return GFX_SPIELER4;
1811     case EL_KAEFER:             return GFX_KAEFER;
1812     case EL_KAEFER_R:           return GFX_KAEFER_R;
1813     case EL_KAEFER_O:           return GFX_KAEFER_O;
1814     case EL_KAEFER_L:           return GFX_KAEFER_L;
1815     case EL_KAEFER_U:           return GFX_KAEFER_U;
1816     case EL_FLIEGER:            return GFX_FLIEGER;
1817     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
1818     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
1819     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
1820     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
1821     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
1822     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
1823     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
1824     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
1825     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
1826     case EL_FIREFLY:            return GFX_FIREFLY;
1827     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
1828     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
1829     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
1830     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
1831     case EL_MAMPFER:            return GFX_MAMPFER;
1832     case EL_ROBOT:              return GFX_ROBOT;
1833     case EL_BETON:              return GFX_BETON;
1834     case EL_DIAMANT:            return GFX_DIAMANT;
1835     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
1836     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
1837     case EL_TROPFEN:            return GFX_TROPFEN;
1838     case EL_BOMBE:              return GFX_BOMBE;
1839     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
1840     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
1841     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
1842     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
1843     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
1844     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
1845     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
1846     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
1847     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
1848     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
1849     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
1850     case EL_LIFE:               return GFX_LIFE;
1851     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
1852     case EL_DYNAMIT:            return GFX_DYNAMIT;
1853     case EL_BADEWANNE:          return GFX_BADEWANNE;
1854     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
1855     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
1856     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
1857     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
1858     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
1859     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
1860     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
1861     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
1862     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
1863     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
1864     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
1865     case EL_PFORTE1:            return GFX_PFORTE1;
1866     case EL_PFORTE2:            return GFX_PFORTE2;
1867     case EL_PFORTE3:            return GFX_PFORTE3;
1868     case EL_PFORTE4:            return GFX_PFORTE4;
1869     case EL_PFORTE1X:           return GFX_PFORTE1X;
1870     case EL_PFORTE2X:           return GFX_PFORTE2X;
1871     case EL_PFORTE3X:           return GFX_PFORTE3X;
1872     case EL_PFORTE4X:           return GFX_PFORTE4X;
1873     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
1874     case EL_PACMAN:             return GFX_PACMAN;
1875     case EL_PACMAN_R:           return GFX_PACMAN_R;
1876     case EL_PACMAN_O:           return GFX_PACMAN_O;
1877     case EL_PACMAN_L:           return GFX_PACMAN_L;
1878     case EL_PACMAN_U:           return GFX_PACMAN_U;
1879     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
1880     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
1881     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
1882     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
1883     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
1884     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
1885     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
1886     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
1887     case EL_MAUER_X:            return GFX_MAUER_X;
1888     case EL_MAUER_Y:            return GFX_MAUER_Y;
1889     case EL_MAUER_XY:           return GFX_MAUER_XY;
1890     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
1891     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
1892     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
1893     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
1894     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
1895     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
1896     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
1897     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
1898     case EL_MAMPFER2:           return GFX_MAMPFER2;
1899     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
1900     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
1901     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
1902     case EL_DYNABOMB:           return GFX_DYNABOMB;
1903     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
1904     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
1905     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
1906     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
1907     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
1908     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
1909     case EL_MAULWURF:           return GFX_MAULWURF;
1910     case EL_PINGUIN:            return GFX_PINGUIN;
1911     case EL_SCHWEIN:            return GFX_SCHWEIN;
1912     case EL_DRACHE:             return GFX_DRACHE;
1913     case EL_SONDE:              return GFX_SONDE;
1914     case EL_PFEIL_L:            return GFX_PFEIL_L;
1915     case EL_PFEIL_R:            return GFX_PFEIL_R;
1916     case EL_PFEIL_O:            return GFX_PFEIL_O;
1917     case EL_PFEIL_U:            return GFX_PFEIL_U;
1918     default:
1919     {
1920       if (IS_CHAR(element))
1921         return GFX_CHAR_START + (element - EL_CHAR_START);
1922       else if (element >= EL_SP_START && element <= EL_SP_END)
1923         return GFX_START_ROCKSMORE + (element - EL_SP_START);
1924       else
1925         return -1;
1926     }
1927   }
1928 }