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