rnd-19990220-1-src
[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 /* tool button identifiers */
35 #define TOOL_CTRL_ID_YES        0
36 #define TOOL_CTRL_ID_NO         1
37 #define TOOL_CTRL_ID_CONFIRM    2
38 #define TOOL_CTRL_ID_PLAYER_1   3
39 #define TOOL_CTRL_ID_PLAYER_2   4
40 #define TOOL_CTRL_ID_PLAYER_3   5
41 #define TOOL_CTRL_ID_PLAYER_4   6
42
43 #define NUM_TOOL_BUTTONS        7
44
45 /* forward declaration for internal use */
46 static int getGraphicAnimationPhase(int, int, int);
47 static void UnmapToolButtons();
48 static void HandleToolButtons(struct GadgetInfo *);
49
50 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
51 static int request_gadget_id = -1;
52
53 void SetDrawtoField(int mode)
54 {
55   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
56   {
57     FX = TILEX;
58     FY = TILEY;
59     BX1 = -1;
60     BY1 = -1;
61     BX2 = SCR_FIELDX;
62     BY2 = SCR_FIELDY;
63     redraw_x1 = 1;
64     redraw_y1 = 1;
65
66     drawto_field = fieldbuffer;
67   }
68   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
69   {
70     FX = SX;
71     FY = SY;
72     BX1 = 0;
73     BY1 = 0;
74     BX2 = SCR_FIELDX - 1;
75     BY2 = SCR_FIELDY - 1;
76     redraw_x1 = 0;
77     redraw_y1 = 0;
78
79     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
80   }
81 }
82
83 void BackToFront()
84 {
85   int x,y;
86   Drawable buffer = (drawto_field == window ? backbuffer : drawto_field);
87
88   if (setup.direct_draw && game_status == PLAYING)
89     redraw_mask &= ~REDRAW_MAIN;
90
91   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
92     redraw_mask |= REDRAW_FIELD;
93
94   if (redraw_mask & REDRAW_FIELD)
95     redraw_mask &= ~REDRAW_TILES;
96
97   if (!redraw_mask)
98     return;
99
100   /* synchronize X11 graphics at this point; if we would synchronize the
101      display immediately after the buffer switching (after the XFlush),
102      this could mean that we have to wait for the graphics to complete,
103      although we could go on doing calculations for the next frame */
104
105   XSync(display, FALSE);
106
107   if (redraw_mask & REDRAW_ALL)
108   {
109     XCopyArea(display, backbuffer, window, gc,
110               0, 0, WIN_XSIZE, WIN_YSIZE,
111               0, 0);
112     redraw_mask = 0;
113   }
114
115   if (redraw_mask & REDRAW_FIELD)
116   {
117     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
118     {
119       XCopyArea(display, backbuffer, window, gc,
120                 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
121                 REAL_SX, REAL_SY);
122     }
123     else
124     {
125       int fx = FX, fy = FY;
126
127       if (setup.soft_scrolling)
128       {
129         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
130         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
131       }
132
133       if (setup.soft_scrolling ||
134           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
135           ABS(ScreenMovPos) == ScrollStepSize ||
136           redraw_tiles > REDRAWTILES_THRESHOLD)
137       {
138         XCopyArea(display, buffer, window, gc, fx, fy, SXSIZE, SYSIZE, SX, SY);
139
140 #ifdef DEBUG
141 #if 0
142         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
143                ScreenGfxPos,
144                (setup.soft_scrolling ?
145                 "setup.soft_scrolling" :
146                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
147                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
148                 ABS(ScreenGfxPos) == ScrollStepSize ?
149                 "ABS(ScreenGfxPos) == ScrollStepSize" :
150                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
151 #endif
152 #endif
153       }
154     }
155     redraw_mask &= ~REDRAW_MAIN;
156   }
157
158   if (redraw_mask & REDRAW_DOORS)
159   {
160     if (redraw_mask & REDRAW_DOOR_1)
161       XCopyArea(display, backbuffer, window, gc,
162                 DX, DY, DXSIZE, DYSIZE,
163                 DX, DY);
164     if (redraw_mask & REDRAW_DOOR_2)
165     {
166       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
167         XCopyArea(display,backbuffer,window,gc,
168                   VX,VY, VXSIZE,VYSIZE,
169                   VX,VY);
170       else
171       {
172         if (redraw_mask & REDRAW_VIDEO_1)
173           XCopyArea(display,backbuffer,window,gc,
174                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
175                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
176                     VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
177         if (redraw_mask & REDRAW_VIDEO_2)
178           XCopyArea(display,backbuffer,window,gc,
179                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
180                     VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
181                     VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
182         if (redraw_mask & REDRAW_VIDEO_3)
183           XCopyArea(display,backbuffer,window,gc,
184                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
185                     VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
186                     VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
187       }
188     }
189     if (redraw_mask & REDRAW_DOOR_3)
190       XCopyArea(display, backbuffer, window, gc,
191                 EX, EY, EXSIZE, EYSIZE,
192                 EX, EY);
193     redraw_mask &= ~REDRAW_DOORS;
194   }
195
196   if (redraw_mask & REDRAW_MICROLEVEL)
197   {
198     XCopyArea(display,backbuffer,window,gc,
199               MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
200               MICROLEV_XPOS, MICROLEV_YPOS);
201     XCopyArea(display,backbuffer,window,gc,
202               SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
203               SX, MICROLABEL_YPOS);
204     redraw_mask &= ~REDRAW_MICROLEVEL;
205   }
206
207   if (redraw_mask & REDRAW_TILES)
208   {
209     for(x=0; x<SCR_FIELDX; x++)
210       for(y=0; y<SCR_FIELDY; y++)
211         if (redraw[redraw_x1 + x][redraw_y1 + y])
212           XCopyArea(display, buffer, window, gc,
213                     FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
214                     SX + x * TILEX, SY + y * TILEY);
215   }
216
217   XFlush(display);
218
219   for(x=0; x<MAX_BUF_XSIZE; x++)
220     for(y=0; y<MAX_BUF_YSIZE; y++)
221       redraw[x][y] = 0;
222   redraw_tiles = 0;
223   redraw_mask = 0;
224 }
225
226 void FadeToFront()
227 {
228 /*
229   long fading_delay = 300;
230
231   if (setup.fading && (redraw_mask & REDRAW_FIELD))
232   {
233 */
234
235 /*
236     int x,y;
237
238     XFillRectangle(display,window,gc,
239                    REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
240     XFlush(display);
241
242     for(i=0;i<2*FULL_SYSIZE;i++)
243     {
244       for(y=0;y<FULL_SYSIZE;y++)
245       {
246         XCopyArea(display,backbuffer,window,gc,
247                   REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
248       }
249       XFlush(display);
250       Delay(10);
251     }
252 */
253
254 /*
255     for(i=1;i<FULL_SYSIZE;i+=2)
256       XCopyArea(display,backbuffer,window,gc,
257                 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
258     XFlush(display);
259     Delay(fading_delay);
260 */
261
262 /*
263     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,0);
264     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
265               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
266     XFlush(display);
267     Delay(fading_delay);
268
269     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,-1);
270     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
271               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
272     XFlush(display);
273     Delay(fading_delay);
274
275     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],0,-1);
276     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
277               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
278     XFlush(display);
279     Delay(fading_delay);
280
281     XSetClipOrigin(display,clip_gc[PIX_FADEMASK],-1,0);
282     XCopyArea(display,backbuffer,window,clip_gc[PIX_FADEMASK],
283               REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE, REAL_SX,REAL_SY);
284     XFlush(display);
285     Delay(fading_delay);
286
287     redraw_mask &= ~REDRAW_MAIN;
288   }
289 */
290
291   BackToFront();
292 }
293
294 void ClearWindow()
295 {
296   XFillRectangle(display, backbuffer, gc,
297                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
298
299   if (setup.soft_scrolling && game_status == PLAYING)
300   {
301     XFillRectangle(display, fieldbuffer, gc, 0, 0, FXSIZE, FYSIZE);
302     SetDrawtoField(DRAW_BUFFERED);
303   }
304   else
305     SetDrawtoField(DRAW_BACKBUFFER);
306
307   if (setup.direct_draw && game_status == PLAYING)
308   {
309     XFillRectangle(display, window, gc,
310                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
311     SetDrawtoField(DRAW_DIRECT);
312   }
313
314   redraw_mask |= REDRAW_FIELD;
315 }
316
317 void DrawTextFCentered(int y, int font_type, char *format, ...)
318 {
319   char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
320   int font_xsize;
321   va_list ap;
322
323   font_xsize = (font_type < FC_SPECIAL1 ? FONT2_XSIZE :
324                 font_type < FC_SPECIAL2 ? FONT3_XSIZE :
325                 font_type < FC_SPECIAL3 ? FONT4_XSIZE :
326                 FONT5_XSIZE);
327
328   va_start(ap, format);
329   vsprintf(buffer, format, ap);
330   va_end(ap);
331
332   DrawText(SX + (SXSIZE - strlen(buffer) * font_xsize) / 2, SY + y,
333            buffer, FS_SMALL, font_type);
334 }
335
336 void DrawTextF(int x, int y, int font_type, char *format, ...)
337 {
338   char buffer[FULL_SXSIZE / FONT5_XSIZE + 10];
339   va_list ap;
340
341   va_start(ap, format);
342   vsprintf(buffer, format, ap);
343   va_end(ap);
344
345   DrawText(SX + x, SY + y, buffer, FS_SMALL, font_type);
346 }
347
348 void DrawText(int x, int y, char *text, int font_size, int font_type)
349 {
350   DrawTextExt(drawto, gc, x, y, text, font_size, font_type);
351
352   if (x < DX)
353     redraw_mask |= REDRAW_FIELD;
354   else if (y < VY)
355     redraw_mask |= REDRAW_DOOR_1;
356 }
357
358 void DrawTextExt(Drawable d, GC gc, int x, int y,
359                  char *text, int font_size, int font_type)
360 {
361   int font_width, font_height, font_start;
362   int font_pixmap;
363   boolean print_inverse = FALSE;
364
365   if (font_size != FS_SMALL && font_size != FS_BIG)
366     font_size = FS_SMALL;
367   if (font_type < FC_RED || font_type > FC_SPECIAL3)
368     font_type = FC_RED;
369
370   font_width = (font_size == FS_BIG ? FONT1_XSIZE :
371                 font_type < FC_SPECIAL1 ? FONT2_XSIZE :
372                 font_type < FC_SPECIAL2 ? FONT3_XSIZE :
373                 font_type < FC_SPECIAL3 ? FONT4_XSIZE :
374                 FONT5_XSIZE);
375   font_height = (font_size == FS_BIG ? FONT1_YSIZE :
376                  font_type < FC_SPECIAL1 ? FONT2_YSIZE :
377                  font_type < FC_SPECIAL2 ? FONT3_YSIZE :
378                  font_type < FC_SPECIAL3 ? FONT4_YSIZE :
379                  FONT5_YSIZE);
380   font_pixmap = (font_size == FS_BIG ? PIX_BIGFONT : PIX_SMALLFONT);
381   font_start = (font_type * (font_size == FS_BIG ? FONT1_YSIZE : FONT2_YSIZE) *
382                 FONT_LINES_PER_FONT);
383
384   if (font_type == FC_SPECIAL3)
385     font_start += (FONT4_YSIZE - FONT2_YSIZE) * FONT_LINES_PER_FONT + 3;
386
387   while (*text)
388   {
389     char c = *text++;
390
391     if (c == '~' && font_size == FS_SMALL && font_type <= FC_YELLOW)
392     {
393       print_inverse = TRUE;
394       continue;
395     }
396
397     if (c >= 'a' && c <= 'z')
398       c = 'A' + (c - 'a');
399     else if (c == 'ä' || c == 'Ä')
400       c = 91;
401     else if (c == 'ö' || c == 'Ö')
402       c = 92;
403     else if (c == 'ü' || c == 'Ãœ')
404       c = 93;
405
406     if (c >= 32 && c <= 95)
407     {
408       int src_x = ((c - 32) % FONT_CHARS_PER_LINE) * font_width;
409       int src_y = ((c - 32) / FONT_CHARS_PER_LINE) * font_height + font_start;
410       int dest_x = x, dest_y = y;
411
412       if (print_inverse)
413       {
414         XCopyArea(display, pix[font_pixmap], d, gc,
415                   FONT_CHARS_PER_LINE * font_width,
416                   3 * font_height + font_start,
417                   font_width, font_height, x, y);
418
419         XSetClipOrigin(display, clip_gc[font_pixmap],
420                        dest_x - src_x, dest_y - src_y);
421         XCopyArea(display, pix[font_pixmap], d, clip_gc[font_pixmap],
422                   0, 0, font_width, font_height, dest_x, dest_y);
423       }
424       else
425         XCopyArea(display, pix[font_pixmap], d, gc,
426                   src_x, src_y, font_width, font_height, dest_x, dest_y);
427     }
428
429     x += font_width;
430   }
431 }
432
433 void DrawAllPlayers()
434 {
435   int i;
436
437   for(i=0; i<MAX_PLAYERS; i++)
438     if (stored_player[i].active)
439       DrawPlayer(&stored_player[i]);
440 }
441
442 void DrawPlayerField(int x, int y)
443 {
444   if (!IS_PLAYER(x, y))
445     return;
446
447   DrawPlayer(PLAYERINFO(x, y));
448 }
449
450 void DrawPlayer(struct PlayerInfo *player)
451 {
452   int jx = player->jx, jy = player->jy;
453   int last_jx = player->last_jx, last_jy = player->last_jy;
454   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
455   int sx = SCREENX(jx), sy = SCREENY(jy);
456   int sxx = 0, syy = 0;
457   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
458   int graphic, phase;
459   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
460
461   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
462     return;
463
464 #if DEBUG
465   if (!IN_LEV_FIELD(jx,jy))
466   {
467     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
468     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
469     printf("DrawPlayerField(): This should never happen!\n");
470     return;
471   }
472 #endif
473
474   if (element == EL_EXPLODING)
475     return;
476
477   /* draw things in the field the player is leaving, if needed */
478
479   if (player_is_moving)
480   {
481     if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
482     {
483       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
484       DrawLevelFieldThruMask(last_jx, last_jy);
485     }
486     else if (last_element == EL_DYNAMIT)
487       DrawDynamite(last_jx, last_jy);
488     else
489       DrawLevelField(last_jx, last_jy);
490
491     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
492     {
493       if (player->GfxPos)
494       {
495         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
496           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FELD_LEER);
497         else
498           DrawLevelElement(next_jx, next_jy, EL_LEERRAUM);
499       }
500       else
501         DrawLevelField(next_jx, next_jy);
502     }
503   }
504
505   if (!IN_SCR_FIELD(sx, sy))
506     return;
507
508   if (setup.direct_draw)
509     SetDrawtoField(DRAW_BUFFERED);
510
511   /* draw things behind the player, if needed */
512
513   if (Store[jx][jy])
514     DrawLevelElement(jx, jy, Store[jx][jy]);
515   else if (element != EL_DYNAMIT && element != EL_DYNABOMB)
516     DrawLevelField(jx, jy);
517
518   /* draw player himself */
519
520   if (game.emulation == EMU_SUPAPLEX)
521   {
522     static int last_dir = MV_LEFT;
523     int action = (player->programmed_action ? player->programmed_action :
524                   player->action);
525     boolean action_moving =
526       (player_is_moving ||
527        ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
528         !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
529
530     graphic = GFX_SP_MURPHY;
531
532     if (player->Pushing)
533     {
534       if (player->MovDir == MV_LEFT)
535         graphic = GFX_MURPHY_PUSH_LEFT;
536       else if (player->MovDir == MV_RIGHT)
537         graphic = GFX_MURPHY_PUSH_RIGHT;
538       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
539         graphic = GFX_MURPHY_PUSH_LEFT;
540       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
541         graphic = GFX_MURPHY_PUSH_RIGHT;
542     }
543     else if (player->snapped)
544     {
545       if (player->MovDir == MV_LEFT)
546         graphic = GFX_MURPHY_SNAP_LEFT;
547       else if (player->MovDir == MV_RIGHT)
548         graphic = GFX_MURPHY_SNAP_RIGHT;
549       else if (player->MovDir == MV_UP)
550         graphic = GFX_MURPHY_SNAP_UP;
551       else if (player->MovDir == MV_DOWN)
552         graphic = GFX_MURPHY_SNAP_DOWN;
553     }
554     else if (action_moving)
555     {
556       if (player->MovDir == MV_LEFT)
557         graphic = GFX_MURPHY_GO_LEFT;
558       else if (player->MovDir == MV_RIGHT)
559         graphic = GFX_MURPHY_GO_RIGHT;
560       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
561         graphic = GFX_MURPHY_GO_LEFT;
562       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
563         graphic = GFX_MURPHY_GO_RIGHT;
564
565       graphic += getGraphicAnimationPhase(3, 2, ANIM_OSCILLATE);
566     }
567
568     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
569       last_dir = player->MovDir;
570   }
571   else
572   {
573     if (player->MovDir == MV_LEFT)
574       graphic =
575         (player->Pushing ? GFX_SPIELER1_PUSH_LEFT : GFX_SPIELER1_LEFT);
576     else if (player->MovDir == MV_RIGHT)
577       graphic =
578         (player->Pushing ? GFX_SPIELER1_PUSH_RIGHT : GFX_SPIELER1_RIGHT);
579     else if (player->MovDir == MV_UP)
580       graphic = GFX_SPIELER1_UP;
581     else        /* MV_DOWN || MV_NO_MOVING */
582       graphic = GFX_SPIELER1_DOWN;
583
584     graphic += player->index_nr * 3 * HEROES_PER_LINE;
585     graphic += player->Frame;
586   }
587
588   if (player->GfxPos)
589   {
590     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
591       sxx = player->GfxPos;
592     else
593       syy = player->GfxPos;
594   }
595
596   if (!setup.soft_scrolling && ScreenMovPos)
597     sxx = syy = 0;
598
599   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, NO_CUTTING);
600
601   if (player->Pushing && player->GfxPos)
602   {
603     int px = SCREENX(next_jx), py = SCREENY(next_jy);
604
605     if (element == EL_SOKOBAN_FELD_LEER ||
606         Feld[next_jx][next_jy] == EL_SOKOBAN_FELD_VOLL)
607       DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT,
608                                  NO_CUTTING);
609     else
610     {
611       int element = Feld[next_jx][next_jy];
612       int graphic = el2gfx(element);
613
614       if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK) && sxx)
615       {
616         int phase = (player->GfxPos / (TILEX / 4));
617
618         if (player->MovDir == MV_LEFT)
619           graphic += phase;
620         else
621           graphic += (phase + 4) % 4;
622       }
623
624       DrawGraphicShifted(px, py, sxx, syy, graphic, NO_CUTTING, NO_MASKING);
625     }
626   }
627
628   /* draw things in front of player (EL_DYNAMIT or EL_DYNABOMB) */
629
630   if (element == EL_DYNAMIT || element == EL_DYNABOMB)
631   {
632     graphic = el2gfx(element);
633
634     if (element == EL_DYNAMIT)
635     {
636       if ((phase = (96 - MovDelay[jx][jy]) / 12) > 6)
637         phase = 6;
638     }
639     else
640     {
641       if ((phase = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
642         phase = 7 - phase;
643     }
644
645     if (game.emulation == EMU_SUPAPLEX)
646       DrawGraphic(sx, sy, GFX_SP_DISK_RED);
647     else
648       DrawGraphicThruMask(sx, sy, graphic + phase);
649   }
650
651   if (player_is_moving && last_element == EL_EXPLODING)
652   {
653     int phase = Frame[last_jx][last_jy];
654     int delay = 2;
655
656     if (phase > 2)
657       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
658                           GFX_EXPLOSION + ((phase - 1) / delay - 1));
659   }
660
661   /* draw elements that stay over the player */
662   /* handle the field the player is leaving ... */
663   if (player_is_moving && IS_OVER_PLAYER(last_element))
664     DrawLevelField(last_jx, last_jy);
665   /* ... and the field the player is entering */
666   if (IS_OVER_PLAYER(element))
667     DrawLevelField(jx, jy);
668
669   if (setup.direct_draw)
670   {
671     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
672     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
673     int x_size = TILEX * (1 + ABS(jx - last_jx));
674     int y_size = TILEY * (1 + ABS(jy - last_jy));
675
676     XCopyArea(display, drawto_field, window, gc,
677               dest_x, dest_y, x_size, y_size, dest_x, dest_y);
678     SetDrawtoField(DRAW_DIRECT);
679   }
680
681   MarkTileDirty(sx,sy);
682 }
683
684 static int getGraphicAnimationPhase(int frames, int delay, int mode)
685 {
686   int phase;
687
688   if (mode == ANIM_OSCILLATE)
689   {
690     int max_anim_frames = 2 * frames - 2;
691     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
692     phase = (phase < frames ? phase : max_anim_frames - phase);
693   }
694   else
695     phase = (FrameCounter % (delay * frames)) / delay;
696
697   if (mode == ANIM_REVERSE)
698     phase = -phase;
699
700   return(phase);
701 }
702
703 void DrawGraphicAnimationExt(int x, int y, int graphic,
704                              int frames, int delay, int mode, int mask_mode)
705 {
706   int phase = getGraphicAnimationPhase(frames, delay, mode);
707
708   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
709   {
710     if (mask_mode == USE_MASKING)
711       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
712     else
713       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
714   }
715 }
716
717 void DrawGraphicAnimation(int x, int y, int graphic,
718                           int frames, int delay, int mode)
719 {
720   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
721 }
722
723 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
724                                   int frames, int delay, int mode)
725 {
726   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
727 }
728
729 void getGraphicSource(int graphic, int *pixmap_nr, int *x, int *y)
730 {
731   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
732   {
733     graphic -= GFX_START_ROCKSSCREEN;
734     *pixmap_nr = PIX_BACK;
735     *x = SX + (graphic % GFX_PER_LINE) * TILEX;
736     *y = SY + (graphic / GFX_PER_LINE) * TILEY;
737   }
738   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
739   {
740     graphic -= GFX_START_ROCKSMORE;
741     *pixmap_nr = PIX_MORE;
742     *x = (graphic % MORE_PER_LINE) * TILEX;
743     *y = (graphic / MORE_PER_LINE) * TILEY;
744   }
745   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
746   {
747     graphic -= GFX_START_ROCKSHEROES;
748     *pixmap_nr = PIX_HEROES;
749     *x = (graphic % HEROES_PER_LINE) * TILEX;
750     *y = (graphic / HEROES_PER_LINE) * TILEY;
751   }
752   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
753   {
754     graphic -= GFX_START_ROCKSFONT;
755     *pixmap_nr = PIX_BIGFONT;
756     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
757     *y = ((graphic / FONT_CHARS_PER_LINE) * TILEY +
758           FC_SPECIAL1 * FONT_LINES_PER_FONT * TILEY);
759   }
760   else
761   {
762     *pixmap_nr = PIX_MORE;
763     *x = 0;
764     *y = 0;
765   }
766 }
767
768 void DrawGraphic(int x, int y, int graphic)
769 {
770 #if DEBUG
771   if (!IN_SCR_FIELD(x,y))
772   {
773     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
774     printf("DrawGraphic(): This should never happen!\n");
775     return;
776   }
777 #endif
778
779   DrawGraphicExt(drawto_field, gc, FX + x*TILEX, FY + y*TILEY, graphic);
780   MarkTileDirty(x,y);
781 }
782
783 void DrawGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
784 {
785   int pixmap_nr;
786   int src_x, src_y;
787
788   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
789   XCopyArea(display, pix[pixmap_nr], d, gc,
790             src_x, src_y, TILEX, TILEY, x, y);
791 }
792
793 void DrawGraphicThruMask(int x, int y, int graphic)
794 {
795 #if DEBUG
796   if (!IN_SCR_FIELD(x,y))
797   {
798     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
799     printf("DrawGraphicThruMask(): This should never happen!\n");
800     return;
801   }
802 #endif
803
804   DrawGraphicThruMaskExt(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
805   MarkTileDirty(x,y);
806 }
807
808 void DrawGraphicThruMaskExt(Drawable d, int dest_x, int dest_y, int graphic)
809 {
810   int tile = graphic;
811   int pixmap_nr;
812   int src_x, src_y;
813   Pixmap src_pixmap;
814   GC drawing_gc;
815
816   if (graphic == GFX_LEERRAUM)
817     return;
818
819   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
820   src_pixmap = pix[pixmap_nr];
821   drawing_gc = clip_gc[pixmap_nr];
822
823   if (tile_clipmask[tile] != None)
824   {
825     XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
826     XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
827     XCopyArea(display, src_pixmap, d, tile_clip_gc,
828               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
829   }
830   else
831   {
832 #if DEBUG
833     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
834 #endif
835
836     XSetClipOrigin(display, drawing_gc, dest_x-src_x, dest_y-src_y);
837     XCopyArea(display, src_pixmap, d, drawing_gc,
838               src_x, src_y, TILEX, TILEY, dest_x, dest_y);
839   }
840 }
841
842 void DrawMiniGraphic(int x, int y, int graphic)
843 {
844   DrawMiniGraphicExt(drawto,gc, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
845   MarkTileDirty(x/2, y/2);
846 }
847
848 void getMiniGraphicSource(int graphic, Pixmap *pixmap, int *x, int *y)
849 {
850   if (graphic >= GFX_START_ROCKSSCREEN && graphic <= GFX_END_ROCKSSCREEN)
851   {
852     graphic -= GFX_START_ROCKSSCREEN;
853     *pixmap = pix[PIX_BACK];
854     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
855     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
856   }
857   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
858   {
859     graphic -= GFX_START_ROCKSMORE;
860     graphic -= ((graphic / MORE_PER_LINE) * MORE_PER_LINE) / 2;
861     *pixmap = pix[PIX_MORE];
862     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
863     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
864   }
865   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
866   {
867     graphic -= GFX_START_ROCKSFONT;
868     *pixmap = pix[PIX_SMALLFONT];
869     *x = (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
870     *y = ((graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE +
871               FC_SPECIAL2 * FONT2_YSIZE * FONT_LINES_PER_FONT);
872   }
873   else
874   {
875     *pixmap = pix[PIX_MORE];
876     *x = MINI_MORE_STARTX;
877     *y = MINI_MORE_STARTY;
878   }
879 }
880
881 void DrawMiniGraphicExt(Drawable d, GC gc, int x, int y, int graphic)
882 {
883   Pixmap pixmap;
884   int src_x, src_y;
885
886   getMiniGraphicSource(graphic, &pixmap, &src_x, &src_y);
887   XCopyArea(display, pixmap, d, gc,
888             src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
889 }
890
891 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
892                         int cut_mode, int mask_mode)
893 {
894   int width = TILEX, height = TILEY;
895   int cx = 0, cy = 0;
896   int src_x, src_y, dest_x, dest_y;
897   int tile = graphic;
898   int pixmap_nr;
899   Pixmap src_pixmap;
900   GC drawing_gc;
901
902   if (graphic < 0)
903   {
904     DrawGraphic(x, y, graphic);
905     return;
906   }
907
908   if (dx || dy)                 /* Verschiebung der Grafik? */
909   {
910     if (x < BX1)                /* Element kommt von links ins Bild */
911     {
912       x = BX1;
913       width = dx;
914       cx = TILEX - dx;
915       dx = 0;
916     }
917     else if (x > BX2)           /* Element kommt von rechts ins Bild */
918     {
919       x = BX2;
920       width = -dx;
921       dx = TILEX + dx;
922     }
923     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
924     {
925       width += dx;
926       cx = -dx;
927       dx = 0;
928     }
929     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
930       width -= dx;
931     else if (dx)                /* allg. Bewegung in x-Richtung */
932       MarkTileDirty(x + SIGN(dx), y);
933
934     if (y < BY1)                /* Element kommt von oben ins Bild */
935     {
936       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
937         return;
938
939       y = BY1;
940       height = dy;
941       cy = TILEY - dy;
942       dy = 0;
943     }
944     else if (y > BY2)           /* Element kommt von unten ins Bild */
945     {
946       y = BY2;
947       height = -dy;
948       dy = TILEY + dy;
949     }
950     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
951     {
952       height += dy;
953       cy = -dy;
954       dy = 0;
955     }
956     else if (dy > 0 && cut_mode == CUT_ABOVE)
957     {
958       if (y == BY2)             /* Element unterhalb des Bildes */
959         return;
960
961       height = dy;
962       cy = TILEY - dy;
963       dy = TILEY;
964       MarkTileDirty(x, y + 1);
965     }                           /* Element verläßt unten das Bild */
966     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
967       height -= dy;
968     else if (dy)                /* allg. Bewegung in y-Richtung */
969       MarkTileDirty(x, y + SIGN(dy));
970   }
971
972   getGraphicSource(graphic, &pixmap_nr, &src_x, &src_y);
973   src_pixmap = pix[pixmap_nr];
974   drawing_gc = clip_gc[pixmap_nr];
975
976   dest_x = FX + x * TILEX + dx;
977   dest_y = FY + y * TILEY + dy;
978
979 #if DEBUG
980   if (!IN_SCR_FIELD(x,y))
981   {
982     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
983     printf("DrawGraphicShifted(): This should never happen!\n");
984     return;
985   }
986 #endif
987
988   if (mask_mode == USE_MASKING)
989   {
990     if (tile_clipmask[tile] != None)
991     {
992       XSetClipMask(display, tile_clip_gc, tile_clipmask[tile]);
993       XSetClipOrigin(display, tile_clip_gc, dest_x, dest_y);
994       XCopyArea(display, src_pixmap, drawto_field, tile_clip_gc,
995                 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
996     }
997     else
998     {
999 #if DEBUG
1000       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1001 #endif
1002
1003       XSetClipOrigin(display, drawing_gc, dest_x - src_x, dest_y - src_y);
1004       XCopyArea(display, src_pixmap, drawto_field, drawing_gc,
1005                 src_x, src_y, width, height, dest_x, dest_y);
1006     }
1007   }
1008   else
1009     XCopyArea(display, src_pixmap, drawto_field, gc,
1010               src_x, src_y, width, height, dest_x, dest_y);
1011
1012   MarkTileDirty(x,y);
1013 }
1014
1015 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1016                                 int cut_mode)
1017 {
1018   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1019 }
1020
1021 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1022                           int cut_mode, int mask_mode)
1023 {
1024   int ux = LEVELX(x), uy = LEVELY(y);
1025   int graphic = el2gfx(element);
1026   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1027   int phase4 = phase8 / 2;
1028   int phase2  = phase8 / 4;
1029   int dir = MovDir[ux][uy];
1030
1031   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1032   {
1033     graphic += 4 * !phase2;
1034
1035     if (dir == MV_UP)
1036       graphic += 1;
1037     else if (dir == MV_LEFT)
1038       graphic += 2;
1039     else if (dir == MV_DOWN)
1040       graphic += 3;
1041   }
1042   else if (element == EL_SP_SNIKSNAK)
1043   {
1044     if (dir == MV_LEFT)
1045       graphic = GFX_SP_SNIKSNAK_LEFT;
1046     else if (dir == MV_RIGHT)
1047       graphic = GFX_SP_SNIKSNAK_RIGHT;
1048     else if (dir == MV_UP)
1049       graphic = GFX_SP_SNIKSNAK_UP;
1050     else
1051       graphic = GFX_SP_SNIKSNAK_DOWN;
1052
1053     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1054   }
1055   else if (element == EL_SP_ELECTRON)
1056   {
1057     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1058   }
1059   else if (element == EL_MAULWURF || element == EL_PINGUIN ||
1060            element == EL_SCHWEIN || element == EL_DRACHE)
1061   {
1062     if (dir == MV_LEFT)
1063       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_LEFT :
1064                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1065                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1066     else if (dir == MV_RIGHT)
1067       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_RIGHT :
1068                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1069                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1070     else if (dir == MV_UP)
1071       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_UP :
1072                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1073                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1074     else
1075       graphic = (element == EL_MAULWURF ? GFX_MAULWURF_DOWN :
1076                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1077                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1078
1079     graphic += phase4;
1080   }
1081   else if (element == EL_SONDE)
1082   {
1083     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1084   }
1085   else if (element == EL_SALZSAEURE)
1086   {
1087     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1088   }
1089   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1090   {
1091     graphic += !phase2;
1092   }
1093   else if ((element == EL_FELSBROCKEN || element == EL_SP_ZONK ||
1094             IS_GEM(element)) && !cut_mode)
1095   {
1096     if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1097     {
1098       if (dir == MV_LEFT)
1099         graphic += (4 - phase4) % 4;
1100       else if (dir == MV_RIGHT)
1101         graphic += phase4;
1102       else
1103         graphic += phase2 * 2;
1104     }
1105     else if (element != EL_SP_INFOTRON)
1106       graphic += phase2;
1107
1108     /*
1109     if (element == EL_SP_ZONK)
1110     {
1111       if (dir == MV_LEFT)
1112         graphic += (4 - phase4) % 4;
1113       else if (dir == MV_RIGHT)
1114         graphic += phase4;
1115       else
1116         graphic += phase2 * 2;
1117     }
1118     else if (element != EL_SP_INFOTRON)
1119       graphic += phase2 * (element == EL_FELSBROCKEN ? 2 : 1);
1120     */
1121
1122   }
1123   else if (element == EL_SIEB_LEER || element == EL_SIEB2_LEER ||
1124            element == EL_SIEB_VOLL || element == EL_SIEB2_VOLL)
1125   {
1126     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1127   }
1128   else if (IS_AMOEBOID(element))
1129   {
1130     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1131     graphic += (x + 2 * y + 4) % 4;
1132   }
1133   else if (element == EL_MAUER_LEBT)
1134   {
1135     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1136
1137     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1138       links_massiv = TRUE;
1139     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1140       rechts_massiv = TRUE;
1141
1142     if (links_massiv && rechts_massiv)
1143       graphic = GFX_MAUERWERK;
1144     else if (links_massiv)
1145       graphic = GFX_MAUER_R;
1146     else if (rechts_massiv)
1147       graphic = GFX_MAUER_L;
1148   }
1149
1150   if (dx || dy)
1151     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1152   else if (mask_mode == USE_MASKING)
1153     DrawGraphicThruMask(x, y, graphic);
1154   else
1155     DrawGraphic(x, y, graphic);
1156 }
1157
1158 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1159                          int cut_mode, int mask_mode)
1160 {
1161   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1162     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1163                          cut_mode, mask_mode);
1164 }
1165
1166 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1167                               int cut_mode)
1168 {
1169   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1170 }
1171
1172 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1173                              int cut_mode)
1174 {
1175   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1176 }
1177
1178 void DrawScreenElementThruMask(int x, int y, int element)
1179 {
1180   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1181 }
1182
1183 void DrawLevelElementThruMask(int x, int y, int element)
1184 {
1185   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1186 }
1187
1188 void DrawLevelFieldThruMask(int x, int y)
1189 {
1190   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1191 }
1192
1193 void ErdreichAnbroeckeln(int x, int y)
1194 {
1195   int i, width, height, cx,cy;
1196   int ux = LEVELX(x), uy = LEVELY(y);
1197   int element, graphic;
1198   int snip = 4;
1199   static int xy[4][2] =
1200   {
1201     { 0, -1 },
1202     { -1, 0 },
1203     { +1, 0 },
1204     { 0, +1 }
1205   };
1206
1207   if (!IN_LEV_FIELD(ux, uy))
1208     return;
1209
1210   element = Feld[ux][uy];
1211
1212   if (element == EL_ERDREICH)
1213   {
1214     if (!IN_SCR_FIELD(x, y))
1215       return;
1216
1217     graphic = GFX_ERDENRAND;
1218
1219     for(i=0; i<4; i++)
1220     {
1221       int uxx, uyy;
1222
1223       uxx = ux + xy[i][0];
1224       uyy = uy + xy[i][1];
1225       if (!IN_LEV_FIELD(uxx, uyy))
1226         element = EL_BETON;
1227       else
1228         element = Feld[uxx][uyy];
1229
1230       if (element == EL_ERDREICH)
1231         continue;
1232
1233       if (i == 1 || i == 2)
1234       {
1235         width = snip;
1236         height = TILEY;
1237         cx = (i == 2 ? TILEX - snip : 0);
1238         cy = 0;
1239       }
1240       else
1241       {
1242         width = TILEX;
1243         height = snip;
1244         cx = 0;
1245         cy = (i == 3 ? TILEY - snip : 0);
1246       }
1247
1248       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1249                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1250                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1251                 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1252     }
1253
1254     MarkTileDirty(x, y);
1255   }
1256   else
1257   {
1258     graphic = GFX_ERDENRAND;
1259
1260     for(i=0; i<4; i++)
1261     {
1262       int xx, yy, uxx, uyy;
1263
1264       xx = x + xy[i][0];
1265       yy = y + xy[i][1];
1266       uxx = ux + xy[i][0];
1267       uyy = uy + xy[i][1];
1268
1269       if (!IN_LEV_FIELD(uxx, uyy) || Feld[uxx][uyy] != EL_ERDREICH ||
1270           !IN_SCR_FIELD(xx, yy))
1271         continue;
1272
1273       if (i == 1 || i == 2)
1274       {
1275         width = snip;
1276         height = TILEY;
1277         cx = (i == 1 ? TILEX - snip : 0);
1278         cy = 0;
1279       }
1280       else
1281       {
1282         width = TILEX;
1283         height = snip;
1284         cx = 0;
1285         cy = (i==0 ? TILEY-snip : 0);
1286       }
1287
1288       XCopyArea(display, pix[PIX_BACK], drawto_field, gc,
1289                 SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1290                 SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1291                 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1292
1293       MarkTileDirty(xx, yy);
1294     }
1295   }
1296 }
1297
1298 void DrawScreenElement(int x, int y, int element)
1299 {
1300   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1301   ErdreichAnbroeckeln(x, y);
1302 }
1303
1304 void DrawLevelElement(int x, int y, int element)
1305 {
1306   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1307     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1308 }
1309
1310 void DrawScreenField(int x, int y)
1311 {
1312   int ux = LEVELX(x), uy = LEVELY(y);
1313   int element;
1314
1315   if (!IN_LEV_FIELD(ux, uy))
1316   {
1317     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1318       element = EL_LEERRAUM;
1319     else
1320       element = BorderElement;
1321
1322     DrawScreenElement(x, y, element);
1323     return;
1324   }
1325
1326   element = Feld[ux][uy];
1327
1328   if (IS_MOVING(ux, uy))
1329   {
1330     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1331     boolean cut_mode = NO_CUTTING;
1332
1333     if (Store[ux][uy] == EL_MORAST_LEER ||
1334         Store[ux][uy] == EL_SIEB_LEER ||
1335         Store[ux][uy] == EL_SIEB2_LEER ||
1336         Store[ux][uy] == EL_AMOEBE_NASS)
1337       cut_mode = CUT_ABOVE;
1338     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1339              Store[ux][uy] == EL_SIEB_VOLL ||
1340              Store[ux][uy] == EL_SIEB2_VOLL)
1341       cut_mode = CUT_BELOW;
1342
1343     if (cut_mode == CUT_ABOVE)
1344       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1345     else
1346       DrawScreenElement(x, y, EL_LEERRAUM);
1347
1348     if (horiz_move)
1349       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1350     else
1351       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1352
1353     if (Store[ux][uy] == EL_SALZSAEURE)
1354       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1355   }
1356   else if (IS_BLOCKED(ux, uy))
1357   {
1358     int oldx, oldy;
1359     int sx, sy;
1360     int horiz_move;
1361     boolean cut_mode = NO_CUTTING;
1362
1363     Blocked2Moving(ux, uy, &oldx, &oldy);
1364     sx = SCREENX(oldx);
1365     sy = SCREENY(oldy);
1366     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1367                   MovDir[oldx][oldy] == MV_RIGHT);
1368
1369     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1370         Store[oldx][oldy] == EL_SIEB_LEER ||
1371         Store[oldx][oldy] == EL_SIEB2_LEER ||
1372         Store[oldx][oldy] == EL_AMOEBE_NASS)
1373       cut_mode = CUT_ABOVE;
1374
1375     DrawScreenElement(x, y, EL_LEERRAUM);
1376     element = Feld[oldx][oldy];
1377
1378     if (horiz_move)
1379       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1380     else
1381       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1382   }
1383   else if (IS_DRAWABLE(element))
1384     DrawScreenElement(x, y, element);
1385   else
1386     DrawScreenElement(x, y, EL_LEERRAUM);
1387 }
1388
1389 void DrawLevelField(int x, int y)
1390 {
1391   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1392     DrawScreenField(SCREENX(x), SCREENY(y));
1393   else if (IS_MOVING(x, y))
1394   {
1395     int newx,newy;
1396
1397     Moving2Blocked(x, y, &newx, &newy);
1398     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1399       DrawScreenField(SCREENX(newx), SCREENY(newy));
1400   }
1401   else if (IS_BLOCKED(x, y))
1402   {
1403     int oldx, oldy;
1404
1405     Blocked2Moving(x, y, &oldx, &oldy);
1406     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1407       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1408   }
1409 }
1410
1411 void DrawMiniElement(int x, int y, int element)
1412 {
1413   int graphic;
1414
1415   if (!element)
1416   {
1417     DrawMiniGraphic(x, y, -1);
1418     return;
1419   }
1420
1421   graphic = el2gfx(element);
1422   DrawMiniGraphic(x, y, graphic);
1423 }
1424
1425 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1426 {
1427   int x = sx + scroll_x, y = sy + scroll_y;
1428
1429   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1430     DrawMiniElement(sx, sy, EL_LEERRAUM);
1431   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1432     DrawMiniElement(sx, sy, Feld[x][y]);
1433   else
1434   {
1435     int steel_type, steel_position;
1436     int border[6][2] =
1437     {
1438       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1439       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1440       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1441       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1442       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1443       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1444     };
1445
1446     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1447     steel_position = (x == -1 && y == -1                        ? 0 :
1448                       x == lev_fieldx && y == -1                ? 1 :
1449                       x == -1 && y == lev_fieldy                ? 2 :
1450                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1451                       x == -1 || x == lev_fieldx                ? 4 :
1452                       y == -1 || y == lev_fieldy                ? 5 : -1);
1453
1454     if (steel_position != -1)
1455       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1456   }
1457 }
1458
1459 void DrawMicroElement(int xpos, int ypos, int element)
1460 {
1461   int graphic;
1462
1463   if (element == EL_LEERRAUM)
1464     return;
1465
1466   graphic = el2gfx(element);
1467
1468   if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1469   {
1470     graphic -= GFX_START_ROCKSMORE;
1471     graphic -= ((graphic / MORE_PER_LINE) * MORE_PER_LINE) / 2;
1472     XCopyArea(display, pix[PIX_MORE], drawto, gc,
1473               MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE) *MICRO_TILEX,
1474               MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE) *MICRO_TILEY,
1475               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1476   }
1477   else
1478     XCopyArea(display, pix[PIX_BACK], drawto, gc,
1479               MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1480               MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1481               MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1482 }
1483
1484 void DrawLevel()
1485 {
1486   int x,y;
1487
1488   ClearWindow();
1489
1490   for(x=BX1; x<=BX2; x++)
1491     for(y=BY1; y<=BY2; y++)
1492       DrawScreenField(x, y);
1493
1494
1495 #if 1
1496
1497   redraw_mask |= REDRAW_FIELD;
1498
1499 #else
1500
1501   if (setup.soft_scrolling)
1502     XCopyArea(display, fieldbuffer, backbuffer, gc,
1503               FX, FY, SXSIZE, SYSIZE, SX, SY);
1504
1505   redraw_mask |= (REDRAW_FIELD | REDRAW_FROM_BACKBUFFER);
1506
1507 #endif
1508
1509 }
1510
1511 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1512 {
1513   int x,y;
1514
1515   for(x=0; x<size_x; x++)
1516     for(y=0; y<size_y; y++)
1517       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1518
1519   redraw_mask |= REDRAW_FIELD;
1520 }
1521
1522 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1523 {
1524   int x, y;
1525
1526   XFillRectangle(display, drawto, gc,
1527                  xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1528
1529   if (lev_fieldx < STD_LEV_FIELDX)
1530     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1531   if (lev_fieldy < STD_LEV_FIELDY)
1532     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1533
1534   xpos += MICRO_TILEX;
1535   ypos += MICRO_TILEY;
1536
1537   for(x=-1; x<=STD_LEV_FIELDX; x++)
1538   {
1539     for(y=-1; y<=STD_LEV_FIELDY; y++)
1540     {
1541       int lx = from_x + x, ly = from_y + y;
1542
1543       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1544         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1545                          Ur[lx][ly]);
1546       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1547         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1548                          BorderElement);
1549     }
1550   }
1551
1552   redraw_mask |= REDRAW_MICROLEVEL;
1553 }
1554
1555 static void DrawMicroLevelLabelExt(int mode)
1556 {
1557   char label_text[100];
1558
1559   XFillRectangle(display, drawto,gc,
1560                  SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1561
1562   strcpy(label_text, (mode == 1 ? level.name :
1563                       mode == 2 ? "created by" :
1564                       mode == 3 ? level.author : ""));
1565
1566   if (strlen(label_text) > 0)
1567   {
1568     int size, lxpos, lypos;
1569
1570     label_text[SXSIZE / FONT4_XSIZE] = '\0';
1571
1572     size = strlen(label_text);
1573     lxpos = SX + (SXSIZE - size * FONT4_XSIZE) / 2;
1574     lypos = MICROLABEL_YPOS;
1575
1576     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1577   }
1578
1579   redraw_mask |= REDRAW_MICROLEVEL;
1580 }
1581
1582 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1583 {
1584   static unsigned long scroll_delay = 0;
1585   static unsigned long label_delay = 0;
1586   static int from_x, from_y, scroll_direction;
1587   static int label_state, label_counter;
1588
1589   if (restart)
1590   {
1591     from_x = from_y = 0;
1592     scroll_direction = MV_RIGHT;
1593     label_state = 1;
1594     label_counter = 0;
1595
1596     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1597     DrawMicroLevelLabelExt(label_state);
1598
1599     /* initialize delay counters */
1600     DelayReached(&scroll_delay, 0);
1601     DelayReached(&label_delay, 0);
1602
1603     return;
1604   }
1605
1606   /* scroll micro level, if needed */
1607   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1608       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1609   {
1610     switch (scroll_direction)
1611     {
1612       case MV_LEFT:
1613         if (from_x > 0)
1614           from_x--;
1615         else
1616           scroll_direction = MV_UP;
1617         break;
1618
1619       case MV_RIGHT:
1620         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1621           from_x++;
1622         else
1623           scroll_direction = MV_DOWN;
1624         break;
1625
1626       case MV_UP:
1627         if (from_y > 0)
1628           from_y--;
1629         else
1630           scroll_direction = MV_RIGHT;
1631         break;
1632
1633       case MV_DOWN:
1634         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1635           from_y++;
1636         else
1637           scroll_direction = MV_LEFT;
1638         break;
1639
1640       default:
1641         break;
1642     }
1643
1644     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1645   }
1646
1647   /* redraw micro level label, if needed */
1648   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1649       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1650       strcmp(level.author, leveldir[leveldir_nr].name) != 0 &&
1651       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1652   {
1653     label_counter = (label_counter + 1) % 23;
1654     label_state = (label_counter >= 0 && label_counter <= 7 ? 1 :
1655                    label_counter >= 9 && label_counter <= 12 ? 2 :
1656                    label_counter >= 14 && label_counter <= 21 ? 3 : 0);
1657     DrawMicroLevelLabelExt(label_state);
1658   }
1659 }
1660
1661 int REQ_in_range(int x, int y)
1662 {
1663   if (y > DY+249 && y < DY+278)
1664   {
1665     if (x > DX+1 && x < DX+48)
1666       return 1;
1667     else if (x > DX+51 && x < DX+98) 
1668       return 2;
1669   }
1670   return 0;
1671 }
1672
1673 boolean Request(char *text, unsigned int req_state)
1674 {
1675   int mx, my, ty, result = -1;
1676   unsigned int old_door_state;
1677
1678 #ifndef MSDOS
1679   /* pause network game while waiting for request to answer */
1680   if (options.network &&
1681       game_status == PLAYING &&
1682       req_state & REQUEST_WAIT_FOR)
1683     SendToServer_PausePlaying();
1684 #endif
1685
1686   old_door_state = GetDoorState();
1687
1688   UnmapAllGadgets();
1689
1690   CloseDoor(DOOR_CLOSE_1);
1691
1692   /* save old door content */
1693   XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1694             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1695             DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1696
1697   /* clear door drawing field */
1698   XFillRectangle(display, drawto, gc, DX, DY, DXSIZE, DYSIZE);
1699
1700   /* write text for request */
1701   for(ty=0; ty<13; ty++)
1702   {
1703     int tx, tl, tc;
1704     char txt[256];
1705
1706     if (!*text)
1707       break;
1708
1709     for(tl=0,tx=0; tx<7; tl++,tx++)
1710     {
1711       tc = *(text + tx);
1712       if (!tc || tc == 32)
1713         break;
1714     }
1715     if (!tl)
1716     { 
1717       text++; 
1718       ty--; 
1719       continue; 
1720     }
1721     sprintf(txt, text); 
1722     txt[tl] = 0;
1723     DrawTextExt(drawto, gc,
1724                 DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1725                 txt, FS_SMALL, FC_YELLOW);
1726     text += tl + (tc == 32 ? 1 : 0);
1727   }
1728
1729   if (req_state & REQ_ASK)
1730   {
1731     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1732     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1733   }
1734   else if (req_state & REQ_CONFIRM)
1735   {
1736     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1737   }
1738   else if (req_state & REQ_PLAYER)
1739   {
1740     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1741     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1742     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1743     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1744   }
1745
1746   /* copy request gadgets to door backbuffer */
1747   XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
1748             DX, DY, DXSIZE, DYSIZE,
1749             DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1750
1751   OpenDoor(DOOR_OPEN_1);
1752
1753 #if 0
1754   ClearEventQueue();
1755 #endif
1756
1757   if (!(req_state & REQUEST_WAIT_FOR))
1758     return(FALSE);
1759
1760   if (game_status != MAINMENU)
1761     InitAnimation();
1762
1763   button_status = MB_RELEASED;
1764
1765   request_gadget_id = -1;
1766
1767   while(result < 0)
1768   {
1769     if (XPending(display))
1770     {
1771       XEvent event;
1772
1773       XNextEvent(display, &event);
1774
1775       switch(event.type)
1776       {
1777         case ButtonPress:
1778         case ButtonRelease:
1779         case MotionNotify:
1780         {
1781           if (event.type == MotionNotify)
1782           {
1783             Window root, child;
1784             int root_x, root_y;
1785             int win_x, win_y;
1786             unsigned int mask;
1787
1788             if (!XQueryPointer(display, window, &root, &child,
1789                                &root_x, &root_y, &win_x, &win_y, &mask))
1790               continue;
1791
1792             if (!button_status)
1793               continue;
1794
1795             motion_status = TRUE;
1796             mx = ((XMotionEvent *) &event)->x;
1797             my = ((XMotionEvent *) &event)->y;
1798           }
1799           else
1800           {
1801             motion_status = FALSE;
1802             mx = ((XButtonEvent *) &event)->x;
1803             my = ((XButtonEvent *) &event)->y;
1804             if (event.type==ButtonPress)
1805               button_status = ((XButtonEvent *) &event)->button;
1806             else
1807               button_status = MB_RELEASED;
1808           }
1809
1810           /* this sets 'request_gadget_id' */
1811           HandleGadgets(mx, my, button_status);
1812
1813           switch(request_gadget_id)
1814           {
1815             case TOOL_CTRL_ID_YES:
1816               result = TRUE;
1817               break;
1818             case TOOL_CTRL_ID_NO:
1819               result = FALSE;
1820               break;
1821             case TOOL_CTRL_ID_CONFIRM:
1822               result = TRUE | FALSE;
1823               break;
1824
1825             case TOOL_CTRL_ID_PLAYER_1:
1826               result = 1;
1827               break;
1828             case TOOL_CTRL_ID_PLAYER_2:
1829               result = 2;
1830               break;
1831             case TOOL_CTRL_ID_PLAYER_3:
1832               result = 3;
1833               break;
1834             case TOOL_CTRL_ID_PLAYER_4:
1835               result = 4;
1836               break;
1837
1838             default:
1839               break;
1840           }
1841
1842           break;
1843         }
1844
1845         case KeyPress:
1846           switch(XLookupKeysym((XKeyEvent *)&event,
1847                                ((XKeyEvent *)&event)->state))
1848           {
1849             case XK_Return:
1850               result = 1;
1851               break;
1852
1853             case XK_Escape:
1854               result = 0;
1855               break;
1856
1857             default:
1858               break;
1859           }
1860           if (req_state & REQ_PLAYER)
1861             result = 0;
1862           break;
1863
1864         case KeyRelease:
1865           key_joystick_mapping = 0;
1866           break;
1867
1868         default:
1869           HandleOtherEvents(&event);
1870           break;
1871       }
1872     }
1873     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1874     {
1875       int joy = AnyJoystick();
1876
1877       if (joy & JOY_BUTTON_1)
1878         result = 1;
1879       else if (joy & JOY_BUTTON_2)
1880         result = 0;
1881     }
1882
1883     DoAnimation();
1884
1885     /* don't eat all CPU time */
1886     Delay(10);
1887   }
1888
1889   if (game_status != MAINMENU)
1890     StopAnimation();
1891
1892   UnmapToolButtons();
1893
1894   if (!(req_state & REQ_STAY_OPEN))
1895   {
1896     CloseDoor(DOOR_CLOSE_1);
1897
1898     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1899     {
1900       XCopyArea(display,pix[PIX_DB_DOOR],pix[PIX_DB_DOOR],gc,
1901                 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1902                 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1903       OpenDoor(DOOR_OPEN_1);
1904     }
1905   }
1906
1907   RemapAllGadgets();
1908
1909 #ifndef MSDOS
1910   /* continue network game after request */
1911   if (options.network &&
1912       game_status == PLAYING &&
1913       req_state & REQUEST_WAIT_FOR)
1914     SendToServer_ContinuePlaying();
1915 #endif
1916
1917   return(result);
1918 }
1919
1920 unsigned int OpenDoor(unsigned int door_state)
1921 {
1922   unsigned int new_door_state;
1923
1924   if (door_state & DOOR_COPY_BACK)
1925   {
1926     XCopyArea(display, pix[PIX_DB_DOOR], pix[PIX_DB_DOOR], gc,
1927               DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
1928               DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1929     door_state &= ~DOOR_COPY_BACK;
1930   }
1931
1932   new_door_state = MoveDoor(door_state);
1933
1934   return(new_door_state);
1935 }
1936
1937 unsigned int CloseDoor(unsigned int door_state)
1938 {
1939   unsigned int new_door_state;
1940
1941   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1942             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1943   XCopyArea(display, backbuffer, pix[PIX_DB_DOOR], gc,
1944             VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
1945
1946   new_door_state = MoveDoor(door_state);
1947
1948   return(new_door_state);
1949 }
1950
1951 unsigned int GetDoorState()
1952 {
1953   return(MoveDoor(DOOR_GET_STATE));
1954 }
1955
1956 unsigned int MoveDoor(unsigned int door_state)
1957 {
1958   static int door1 = DOOR_OPEN_1;
1959   static int door2 = DOOR_CLOSE_2;
1960   static unsigned long door_delay = 0;
1961   int x, start, stepsize = 2;
1962   unsigned long door_delay_value = stepsize * 5;
1963
1964   if (door_state == DOOR_GET_STATE)
1965     return(door1 | door2);
1966
1967   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
1968     door_state &= ~DOOR_OPEN_1;
1969   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
1970     door_state &= ~DOOR_CLOSE_1;
1971   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
1972     door_state &= ~DOOR_OPEN_2;
1973   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
1974     door_state &= ~DOOR_CLOSE_2;
1975
1976   if (setup.quick_doors)
1977   {
1978     stepsize = 20;
1979     door_delay_value = 0;
1980     StopSound(SND_OEFFNEN);
1981   }
1982
1983   if (door_state & DOOR_ACTION)
1984   {
1985     if (!(door_state & DOOR_NO_DELAY))
1986       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
1987
1988     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
1989
1990     for(x=start; x<=DXSIZE; x+=stepsize)
1991     {
1992       WaitUntilDelayReached(&door_delay, door_delay_value);
1993
1994       if (door_state & DOOR_ACTION_1)
1995       {
1996         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
1997         int j = (DXSIZE - i) / 3;
1998
1999         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2000                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2001                   DXSIZE,DYSIZE - i/2, DX, DY);
2002
2003         XFillRectangle(display, drawto, gc, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2004
2005         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2006                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2007         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2008                   DXSIZE, DOOR_GFX_PAGEY1, i, 77, DX + DXSIZE - i, DY + j);
2009         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2010                   DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63, DX + DXSIZE - i,
2011                   DY + 140 + j);
2012         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2013                        DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2014         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2015                   DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j, DX, DY);
2016         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2017                   DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63, DX, DY + 140 - j);
2018
2019         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2020                   DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2021                   DX, DY + 77 - j);
2022         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2023                   DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2024                   DX, DY + 203 - j);
2025         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2026                        DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2027         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2028                   DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2029                   DX + DXSIZE - i, DY + 77 + j);
2030         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2031                   DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2032                   DX + DXSIZE - i, DY + 203 + j);
2033
2034         redraw_mask |= REDRAW_DOOR_1;
2035       }
2036
2037       if (door_state & DOOR_ACTION_2)
2038       {
2039         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2040         int j = (VXSIZE - i) / 3;
2041
2042         XCopyArea(display, pix[PIX_DB_DOOR], drawto, gc,
2043                   DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2044                   VXSIZE, VYSIZE - i/2, VX, VY);
2045
2046         XFillRectangle(display, drawto, gc, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2047
2048         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2049                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2050         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2051                   VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2, VX + VXSIZE-i, VY+j);
2052         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2053                        VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2054         XCopyArea(display, pix[PIX_DOOR], drawto,clip_gc[PIX_DOOR],
2055                   VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j, VX, VY);
2056
2057         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2058                   VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2,
2059                   VX, VY + VYSIZE / 2 - j);
2060         XSetClipOrigin(display, clip_gc[PIX_DOOR],
2061                        VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2062         XCopyArea(display, pix[PIX_DOOR], drawto, clip_gc[PIX_DOOR],
2063                   VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2, i, VYSIZE / 2 - j,
2064                   VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2065
2066         redraw_mask |= REDRAW_DOOR_2;
2067       }
2068
2069       BackToFront();
2070
2071       if (game_status == MAINMENU)
2072         DoAnimation();
2073     }
2074   }
2075
2076   if (setup.quick_doors)
2077     StopSound(SND_OEFFNEN);
2078
2079   if (door_state & DOOR_ACTION_1)
2080     door1 = door_state & DOOR_ACTION_1;
2081   if (door_state & DOOR_ACTION_2)
2082     door2 = door_state & DOOR_ACTION_2;
2083
2084   return (door1 | door2);
2085 }
2086
2087 void DrawSpecialEditorDoor()
2088 {
2089   /* draw bigger toolbox window */
2090   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2091             DOOR_GFX_PAGEX7, 60, 108, 56, EX - 4, EY - 12);
2092
2093   /* draw background for level selection gadgets */
2094   XCopyArea(display, pix[PIX_DOOR], drawto, gc,
2095             DOOR_GFX_PAGEX7, 0, 108, 60, EX - 4, 0);
2096
2097   redraw_mask |= REDRAW_ALL;
2098 }
2099
2100 void UndrawSpecialEditorDoor()
2101 {
2102   /* draw normal tape recorder window */
2103   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2104             562, 344, 108, 56, EX - 4, EY - 12);
2105
2106   /* draw game title */
2107   XCopyArea(display, pix[PIX_BACK], drawto, gc,
2108             562, 0, 108, 60, EX - 4, 0);
2109
2110   redraw_mask |= REDRAW_ALL;
2111 }
2112
2113 int ReadPixel(Drawable d, int x, int y)
2114 {
2115   XImage *pixel_image;
2116   unsigned long pixel_value;
2117
2118   pixel_image = XGetImage(display, d, x, y, 1, 1, AllPlanes, ZPixmap);
2119   pixel_value = XGetPixel(pixel_image, 0, 0);
2120
2121   XDestroyImage(pixel_image);
2122
2123   return pixel_value;
2124 }
2125
2126 /* ---------- new tool button stuff ---------------------------------------- */
2127
2128 /* graphic position values for tool buttons */
2129 #define TOOL_BUTTON_YES_XPOS            2
2130 #define TOOL_BUTTON_YES_YPOS            250
2131 #define TOOL_BUTTON_YES_GFX_YPOS        0
2132 #define TOOL_BUTTON_YES_XSIZE           46
2133 #define TOOL_BUTTON_YES_YSIZE           28
2134 #define TOOL_BUTTON_NO_XPOS             52
2135 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2136 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2137 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2138 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2139 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2140 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2141 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2142 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2143 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2144 #define TOOL_BUTTON_PLAYER_XSIZE        30
2145 #define TOOL_BUTTON_PLAYER_YSIZE        30
2146 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2147 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2148 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2149 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2150 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2151                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2152 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2153                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2154 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2155                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2156 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2157                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2158 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2159                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2160 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2161                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2162 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2163                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2164 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2165                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2166
2167 static struct
2168 {
2169   int xpos, ypos;
2170   int x, y;
2171   int width, height;
2172   int gadget_id;
2173   char *infotext;
2174 } toolbutton_info[NUM_TOOL_BUTTONS] =
2175 {
2176   {
2177     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2178     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2179     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2180     TOOL_CTRL_ID_YES,
2181     "yes"
2182   },
2183   {
2184     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2185     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2186     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2187     TOOL_CTRL_ID_NO,
2188     "no"
2189   },
2190   {
2191     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2192     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2193     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2194     TOOL_CTRL_ID_CONFIRM,
2195     "confirm"
2196   },
2197   {
2198     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2199     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2200     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2201     TOOL_CTRL_ID_PLAYER_1,
2202     "player 1"
2203   },
2204   {
2205     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2206     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2207     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2208     TOOL_CTRL_ID_PLAYER_2,
2209     "player 2"
2210   },
2211   {
2212     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2213     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2214     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2215     TOOL_CTRL_ID_PLAYER_3,
2216     "player 3"
2217   },
2218   {
2219     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2220     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2221     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2222     TOOL_CTRL_ID_PLAYER_4,
2223     "player 4"
2224   }
2225 };
2226
2227 static void DoNotDisplayInfoText(void *ptr)
2228 {
2229   return;
2230 }
2231
2232 void CreateToolButtons()
2233 {
2234   int i;
2235
2236   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2237   {
2238     Pixmap gd_pixmap = pix[PIX_DOOR];
2239     Pixmap deco_pixmap = None;
2240     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2241     struct GadgetInfo *gi;
2242     unsigned long event_mask;
2243     int gd_xoffset, gd_yoffset;
2244     int gd_x1, gd_x2, gd_y;
2245     int id = i;
2246
2247     event_mask = GD_EVENT_RELEASED;
2248
2249     gd_xoffset = toolbutton_info[i].xpos;
2250     gd_yoffset = toolbutton_info[i].ypos;
2251     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2252     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2253     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2254
2255     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2256     {
2257       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2258                            &deco_pixmap, &deco_x, &deco_y);
2259       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2260       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2261     }
2262
2263     gi = CreateGadget(GDI_CUSTOM_ID, id,
2264                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2265                       GDI_X, DX + toolbutton_info[i].x,
2266                       GDI_Y, DY + toolbutton_info[i].y,
2267                       GDI_WIDTH, toolbutton_info[i].width,
2268                       GDI_HEIGHT, toolbutton_info[i].height,
2269                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2270                       GDI_STATE, GD_BUTTON_UNPRESSED,
2271                       GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y,
2272                       GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y,
2273                       GDI_DECORATION_DESIGN, deco_pixmap, deco_x, deco_y,
2274                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2275                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2276                       GDI_DECORATION_SHIFTING, 1, 1,
2277                       GDI_EVENT_MASK, event_mask,
2278                       GDI_CALLBACK_ACTION, HandleToolButtons,
2279                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2280                       GDI_END);
2281
2282     if (gi == NULL)
2283       Error(ERR_EXIT, "cannot create gadget");
2284
2285     tool_gadget[id] = gi;
2286   }
2287 }
2288
2289 static void UnmapToolButtons()
2290 {
2291   int i;
2292
2293   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2294     UnmapGadget(tool_gadget[i]);
2295 }
2296
2297 static void HandleToolButtons(struct GadgetInfo *gi)
2298 {
2299   request_gadget_id = gi->custom_id;
2300 }
2301
2302 int el2gfx(int element)
2303 {
2304   switch(element)
2305   {
2306     case EL_LEERRAUM:           return -1;
2307     case EL_ERDREICH:           return GFX_ERDREICH;
2308     case EL_MAUERWERK:          return GFX_MAUERWERK;
2309     case EL_FELSBODEN:          return GFX_FELSBODEN;
2310     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2311     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2312     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2313     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2314     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2315     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2316     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2317     case EL_SPIELER1:           return GFX_SPIELER1;
2318     case EL_SPIELER2:           return GFX_SPIELER2;
2319     case EL_SPIELER3:           return GFX_SPIELER3;
2320     case EL_SPIELER4:           return GFX_SPIELER4;
2321     case EL_KAEFER:             return GFX_KAEFER;
2322     case EL_KAEFER_R:           return GFX_KAEFER_R;
2323     case EL_KAEFER_O:           return GFX_KAEFER_O;
2324     case EL_KAEFER_L:           return GFX_KAEFER_L;
2325     case EL_KAEFER_U:           return GFX_KAEFER_U;
2326     case EL_FLIEGER:            return GFX_FLIEGER;
2327     case EL_FLIEGER_R:          return GFX_FLIEGER_R;
2328     case EL_FLIEGER_O:          return GFX_FLIEGER_O;
2329     case EL_FLIEGER_L:          return GFX_FLIEGER_L;
2330     case EL_FLIEGER_U:          return GFX_FLIEGER_U;
2331     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2332     case EL_BUTTERFLY_R:        return GFX_BUTTERFLY_R;
2333     case EL_BUTTERFLY_O:        return GFX_BUTTERFLY_O;
2334     case EL_BUTTERFLY_L:        return GFX_BUTTERFLY_L;
2335     case EL_BUTTERFLY_U:        return GFX_BUTTERFLY_U;
2336     case EL_FIREFLY:            return GFX_FIREFLY;
2337     case EL_FIREFLY_R:          return GFX_FIREFLY_R;
2338     case EL_FIREFLY_O:          return GFX_FIREFLY_O;
2339     case EL_FIREFLY_L:          return GFX_FIREFLY_L;
2340     case EL_FIREFLY_U:          return GFX_FIREFLY_U;
2341     case EL_MAMPFER:            return GFX_MAMPFER;
2342     case EL_ROBOT:              return GFX_ROBOT;
2343     case EL_BETON:              return GFX_BETON;
2344     case EL_DIAMANT:            return GFX_DIAMANT;
2345     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2346     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2347     case EL_TROPFEN:            return GFX_TROPFEN;
2348     case EL_BOMBE:              return GFX_BOMBE;
2349     case EL_SIEB_INAKTIV:       return GFX_SIEB_INAKTIV;
2350     case EL_SIEB_LEER:          return GFX_SIEB_LEER;
2351     case EL_SIEB_VOLL:          return GFX_SIEB_VOLL;
2352     case EL_SIEB_TOT:           return GFX_SIEB_TOT;
2353     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2354     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2355     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2356     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2357     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2358     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2359     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2360     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2361     case EL_LIFE:               return GFX_LIFE;
2362     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2363     case EL_DYNAMIT:            return GFX_DYNAMIT;
2364     case EL_BADEWANNE:          return GFX_BADEWANNE;
2365     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2366     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2367     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2368     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2369     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2370     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2371     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2372     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2373     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2374     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2375     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2376     case EL_PFORTE1:            return GFX_PFORTE1;
2377     case EL_PFORTE2:            return GFX_PFORTE2;
2378     case EL_PFORTE3:            return GFX_PFORTE3;
2379     case EL_PFORTE4:            return GFX_PFORTE4;
2380     case EL_PFORTE1X:           return GFX_PFORTE1X;
2381     case EL_PFORTE2X:           return GFX_PFORTE2X;
2382     case EL_PFORTE3X:           return GFX_PFORTE3X;
2383     case EL_PFORTE4X:           return GFX_PFORTE4X;
2384     case EL_DYNAMIT_AUS:        return GFX_DYNAMIT_AUS;
2385     case EL_PACMAN:             return GFX_PACMAN;
2386     case EL_PACMAN_R:           return GFX_PACMAN_R;
2387     case EL_PACMAN_O:           return GFX_PACMAN_O;
2388     case EL_PACMAN_L:           return GFX_PACMAN_L;
2389     case EL_PACMAN_U:           return GFX_PACMAN_U;
2390     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2391     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2392     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2393     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2394     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2395     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2396     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2397     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2398     case EL_MAUER_X:            return GFX_MAUER_X;
2399     case EL_MAUER_Y:            return GFX_MAUER_Y;
2400     case EL_MAUER_XY:           return GFX_MAUER_XY;
2401     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2402     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2403     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2404     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2405     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2406     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2407     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2408     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2409     case EL_MAMPFER2:           return GFX_MAMPFER2;
2410     case EL_SIEB2_INAKTIV:      return GFX_SIEB2_INAKTIV;
2411     case EL_SIEB2_LEER:         return GFX_SIEB2_LEER;
2412     case EL_SIEB2_VOLL:         return GFX_SIEB2_VOLL;
2413     case EL_SIEB2_TOT:          return GFX_SIEB2_TOT;
2414     case EL_DYNABOMB:           return GFX_DYNABOMB;
2415     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2416     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2417     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2418     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2419     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2420     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2421     case EL_MAULWURF:           return GFX_MAULWURF;
2422     case EL_PINGUIN:            return GFX_PINGUIN;
2423     case EL_SCHWEIN:            return GFX_SCHWEIN;
2424     case EL_DRACHE:             return GFX_DRACHE;
2425     case EL_SONDE:              return GFX_SONDE;
2426     case EL_PFEIL_L:            return GFX_PFEIL_L;
2427     case EL_PFEIL_R:            return GFX_PFEIL_R;
2428     case EL_PFEIL_O:            return GFX_PFEIL_O;
2429     case EL_PFEIL_U:            return GFX_PFEIL_U;
2430     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2431     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2432     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2433     case EL_SP_ZONK:            return GFX_SP_ZONK;
2434       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2435     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2436     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2437     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2438     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2439     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2440     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2441     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2442     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2443     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2444     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2445     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2446     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2447     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2448     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2449     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2450     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2451     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2452     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2453
2454     default:
2455     {
2456       if (IS_CHAR(element))
2457         return GFX_CHAR_START + (element - EL_CHAR_START);
2458       else if (element >= EL_SP_START && element <= EL_SP_END)
2459       {
2460         int nr_element = element - EL_SP_START;
2461         int gfx_per_line = 8;
2462         int nr_graphic =
2463           (nr_element / gfx_per_line) * MORE_PER_LINE +
2464           (nr_element % gfx_per_line);
2465
2466         return GFX_START_ROCKSMORE + nr_graphic;
2467       }
2468       else
2469         return -1;
2470     }
2471   }
2472 }