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