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