rnd-20001203-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 *  Rocks'n'Diamonds -- McDuffin Strikes Back!              *
3 *----------------------------------------------------------*
4 *  (c) 1995-98 Artsoft Entertainment                       *
5 *              Holger Schemel                              *
6 *              Oststrasse 11a                              *
7 *              33604 Bielefeld                             *
8 *              phone: ++49 +521 290471                     *
9 *              email: aeglos@valinor.owl.de                *
10 *----------------------------------------------------------*
11 *  tools.c                                                 *
12 ***********************************************************/
13
14 #include <stdarg.h>
15
16 #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, 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, (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, FX + x*TILEX, FY + y*TILEY, graphic);
881   MarkTileDirty(x,y);
882 }
883
884 void DrawGraphicExt(DrawBuffer bitmap, 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], bitmap, 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[bitmap_nr];
921   drawing_gc = pix[bitmap_nr]->stored_clip_gc;
922
923   if (tile_clipmask[tile] != None)
924   {
925     SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
926     SetClipOrigin(src_bitmap, 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(src_bitmap, 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, 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, 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   Bitmap src_bitmap;
1015   GC drawing_gc;
1016
1017   if (graphic < 0)
1018   {
1019     DrawGraphic(x, y, graphic);
1020     return;
1021   }
1022
1023   if (dx || dy)                 /* Verschiebung der Grafik? */
1024   {
1025     if (x < BX1)                /* Element kommt von links ins Bild */
1026     {
1027       x = BX1;
1028       width = dx;
1029       cx = TILEX - dx;
1030       dx = 0;
1031     }
1032     else if (x > BX2)           /* Element kommt von rechts ins Bild */
1033     {
1034       x = BX2;
1035       width = -dx;
1036       dx = TILEX + dx;
1037     }
1038     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
1039     {
1040       width += dx;
1041       cx = -dx;
1042       dx = 0;
1043     }
1044     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
1045       width -= dx;
1046     else if (dx)                /* allg. Bewegung in x-Richtung */
1047       MarkTileDirty(x + SIGN(dx), y);
1048
1049     if (y < BY1)                /* Element kommt von oben ins Bild */
1050     {
1051       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
1052         return;
1053
1054       y = BY1;
1055       height = dy;
1056       cy = TILEY - dy;
1057       dy = 0;
1058     }
1059     else if (y > BY2)           /* Element kommt von unten ins Bild */
1060     {
1061       y = BY2;
1062       height = -dy;
1063       dy = TILEY + dy;
1064     }
1065     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
1066     {
1067       height += dy;
1068       cy = -dy;
1069       dy = 0;
1070     }
1071     else if (dy > 0 && cut_mode == CUT_ABOVE)
1072     {
1073       if (y == BY2)             /* Element unterhalb des Bildes */
1074         return;
1075
1076       height = dy;
1077       cy = TILEY - dy;
1078       dy = TILEY;
1079       MarkTileDirty(x, y + 1);
1080     }                           /* Element verläßt unten das Bild */
1081     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1082       height -= dy;
1083     else if (dy)                /* allg. Bewegung in y-Richtung */
1084       MarkTileDirty(x, y + SIGN(dy));
1085   }
1086
1087   getGraphicSource(graphic, &bitmap_nr, &src_x, &src_y);
1088   src_bitmap = pix[bitmap_nr];
1089   drawing_gc = pix[bitmap_nr]->stored_clip_gc;
1090
1091   src_x += cx;
1092   src_y += cy;
1093
1094   dest_x = FX + x * TILEX + dx;
1095   dest_y = FY + y * TILEY + dy;
1096
1097 #if DEBUG
1098   if (!IN_SCR_FIELD(x,y))
1099   {
1100     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1101     printf("DrawGraphicShifted(): This should never happen!\n");
1102     return;
1103   }
1104 #endif
1105
1106   if (mask_mode == USE_MASKING)
1107   {
1108     if (tile_clipmask[tile] != None)
1109     {
1110       SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
1111       SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y);
1112       BlitBitmapMasked(src_bitmap, drawto_field,
1113                        src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1114     }
1115     else
1116     {
1117 #if DEBUG
1118 #ifndef TARGET_SDL
1119       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1120 #endif
1121 #endif
1122
1123       SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1124       BlitBitmapMasked(src_bitmap, drawto_field,
1125                        src_x, src_y, width, height, dest_x, dest_y);
1126     }
1127   }
1128   else
1129     BlitBitmap(pix[bitmap_nr], drawto_field,
1130                src_x, src_y, width, height, dest_x, dest_y);
1131
1132   MarkTileDirty(x,y);
1133 }
1134
1135 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1136                                 int cut_mode)
1137 {
1138   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1139 }
1140
1141 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1142                           int cut_mode, int mask_mode)
1143 {
1144   int ux = LEVELX(x), uy = LEVELY(y);
1145   int graphic = el2gfx(element);
1146   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1147   int phase4 = phase8 / 2;
1148   int phase2  = phase8 / 4;
1149   int dir = MovDir[ux][uy];
1150
1151   if (element == EL_PACMAN || element == EL_KAEFER || element == EL_FLIEGER)
1152   {
1153     graphic += 4 * !phase2;
1154
1155     if (dir == MV_UP)
1156       graphic += 1;
1157     else if (dir == MV_LEFT)
1158       graphic += 2;
1159     else if (dir == MV_DOWN)
1160       graphic += 3;
1161   }
1162   else if (element == EL_SP_SNIKSNAK)
1163   {
1164     if (dir == MV_LEFT)
1165       graphic = GFX_SP_SNIKSNAK_LEFT;
1166     else if (dir == MV_RIGHT)
1167       graphic = GFX_SP_SNIKSNAK_RIGHT;
1168     else if (dir == MV_UP)
1169       graphic = GFX_SP_SNIKSNAK_UP;
1170     else
1171       graphic = GFX_SP_SNIKSNAK_DOWN;
1172
1173     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1174   }
1175   else if (element == EL_SP_ELECTRON)
1176   {
1177     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1178   }
1179   else if (element == EL_MOLE || element == EL_PINGUIN ||
1180            element == EL_SCHWEIN || element == EL_DRACHE)
1181   {
1182     if (dir == MV_LEFT)
1183       graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1184                  element == EL_PINGUIN ? GFX_PINGUIN_LEFT :
1185                  element == EL_SCHWEIN ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1186     else if (dir == MV_RIGHT)
1187       graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1188                  element == EL_PINGUIN ? GFX_PINGUIN_RIGHT :
1189                  element == EL_SCHWEIN ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1190     else if (dir == MV_UP)
1191       graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1192                  element == EL_PINGUIN ? GFX_PINGUIN_UP :
1193                  element == EL_SCHWEIN ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1194     else
1195       graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1196                  element == EL_PINGUIN ? GFX_PINGUIN_DOWN :
1197                  element == EL_SCHWEIN ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1198
1199     graphic += phase4;
1200   }
1201   else if (element == EL_SONDE)
1202   {
1203     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_NORMAL);
1204   }
1205   else if (element == EL_SALZSAEURE)
1206   {
1207     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_NORMAL);
1208   }
1209   else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
1210   {
1211     graphic += !phase2;
1212   }
1213   else if (element == EL_BALLOON)
1214   {
1215     graphic += phase4;
1216   }
1217   else if ((element == EL_FELSBROCKEN ||
1218             element == EL_SP_ZONK ||
1219             element == EL_BD_ROCK ||
1220             IS_GEM(element)) && !cut_mode)
1221   {
1222     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1223     {
1224       if (element == EL_FELSBROCKEN ||
1225           element == EL_SP_ZONK ||
1226           element == EL_BD_ROCK)
1227       {
1228         if (dir == MV_LEFT)
1229           graphic += (4 - phase4) % 4;
1230         else if (dir == MV_RIGHT)
1231           graphic += phase4;
1232         else
1233           graphic += phase2 * 2;
1234       }
1235       else if (element != EL_SP_INFOTRON)
1236         graphic += phase2;
1237     }
1238   }
1239   else if (element == EL_MAGIC_WALL_EMPTY ||
1240            element == EL_MAGIC_WALL_BD_EMPTY ||
1241            element == EL_MAGIC_WALL_FULL ||
1242            element == EL_MAGIC_WALL_BD_FULL)
1243   {
1244     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1245   }
1246   else if (IS_AMOEBOID(element))
1247   {
1248     graphic = (element == EL_AMOEBE_TOT ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1249     graphic += (x + 2 * y + 4) % 4;
1250   }
1251   else if (element == EL_MAUER_LEBT)
1252   {
1253     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1254
1255     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1256       links_massiv = TRUE;
1257     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1258       rechts_massiv = TRUE;
1259
1260     if (links_massiv && rechts_massiv)
1261       graphic = GFX_MAUERWERK;
1262     else if (links_massiv)
1263       graphic = GFX_MAUER_R;
1264     else if (rechts_massiv)
1265       graphic = GFX_MAUER_L;
1266   }
1267   else if ((element == EL_INVISIBLE_STEEL ||
1268             element == EL_UNSICHTBAR ||
1269             element == EL_SAND_INVISIBLE) && game.light_time_left)
1270   {
1271     graphic = (element == EL_INVISIBLE_STEEL ? GFX_INVISIBLE_STEEL_ON :
1272                element == EL_UNSICHTBAR ? GFX_UNSICHTBAR_ON :
1273                GFX_SAND_INVISIBLE_ON);
1274   }
1275
1276   if (dx || dy)
1277     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1278   else if (mask_mode == USE_MASKING)
1279     DrawGraphicThruMask(x, y, graphic);
1280   else
1281     DrawGraphic(x, y, graphic);
1282 }
1283
1284 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1285                          int cut_mode, int mask_mode)
1286 {
1287   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1288     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1289                          cut_mode, mask_mode);
1290 }
1291
1292 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1293                               int cut_mode)
1294 {
1295   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1296 }
1297
1298 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1299                              int cut_mode)
1300 {
1301   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1302 }
1303
1304 void DrawScreenElementThruMask(int x, int y, int element)
1305 {
1306   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1307 }
1308
1309 void DrawLevelElementThruMask(int x, int y, int element)
1310 {
1311   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1312 }
1313
1314 void DrawLevelFieldThruMask(int x, int y)
1315 {
1316   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1317 }
1318
1319 void ErdreichAnbroeckeln(int x, int y)
1320 {
1321   int i, width, height, cx,cy;
1322   int ux = LEVELX(x), uy = LEVELY(y);
1323   int element, graphic;
1324   int snip = 4;
1325   static int xy[4][2] =
1326   {
1327     { 0, -1 },
1328     { -1, 0 },
1329     { +1, 0 },
1330     { 0, +1 }
1331   };
1332
1333   if (!IN_LEV_FIELD(ux, uy))
1334     return;
1335
1336   element = Feld[ux][uy];
1337
1338   if (element == EL_ERDREICH ||
1339       element == EL_LANDMINE ||
1340       element == EL_TRAP_INACTIVE ||
1341       element == EL_TRAP_ACTIVE)
1342   {
1343     if (!IN_SCR_FIELD(x, y))
1344       return;
1345
1346     graphic = GFX_ERDENRAND;
1347
1348     for(i=0; i<4; i++)
1349     {
1350       int uxx, uyy;
1351
1352       uxx = ux + xy[i][0];
1353       uyy = uy + xy[i][1];
1354       if (!IN_LEV_FIELD(uxx, uyy))
1355         element = EL_BETON;
1356       else
1357         element = Feld[uxx][uyy];
1358
1359       if (element == EL_ERDREICH ||
1360           element == EL_LANDMINE ||
1361           element == EL_TRAP_INACTIVE ||
1362           element == EL_TRAP_ACTIVE)
1363         continue;
1364
1365       if (i == 1 || i == 2)
1366       {
1367         width = snip;
1368         height = TILEY;
1369         cx = (i == 2 ? TILEX - snip : 0);
1370         cy = 0;
1371       }
1372       else
1373       {
1374         width = TILEX;
1375         height = snip;
1376         cx = 0;
1377         cy = (i == 3 ? TILEY - snip : 0);
1378       }
1379
1380       BlitBitmap(pix[PIX_BACK], drawto_field,
1381                  SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1382                  SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1383                  width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1384     }
1385
1386     MarkTileDirty(x, y);
1387   }
1388   else
1389   {
1390     graphic = GFX_ERDENRAND;
1391
1392     for(i=0; i<4; i++)
1393     {
1394       int xx, yy, uxx, uyy;
1395
1396       xx = x + xy[i][0];
1397       yy = y + xy[i][1];
1398       uxx = ux + xy[i][0];
1399       uyy = uy + xy[i][1];
1400
1401       if (!IN_LEV_FIELD(uxx, uyy) ||
1402           (Feld[uxx][uyy] != EL_ERDREICH &&
1403            Feld[uxx][uyy] != EL_LANDMINE &&
1404            Feld[uxx][uyy] != EL_TRAP_INACTIVE &&
1405            Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1406           !IN_SCR_FIELD(xx, yy))
1407         continue;
1408
1409       if (i == 1 || i == 2)
1410       {
1411         width = snip;
1412         height = TILEY;
1413         cx = (i == 1 ? TILEX - snip : 0);
1414         cy = 0;
1415       }
1416       else
1417       {
1418         width = TILEX;
1419         height = snip;
1420         cx = 0;
1421         cy = (i==0 ? TILEY-snip : 0);
1422       }
1423
1424       BlitBitmap(pix[PIX_BACK], drawto_field,
1425                  SX + (graphic % GFX_PER_LINE) * TILEX + cx,
1426                  SY + (graphic / GFX_PER_LINE) * TILEY + cy,
1427                  width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1428
1429       MarkTileDirty(xx, yy);
1430     }
1431   }
1432 }
1433
1434 void DrawScreenElement(int x, int y, int element)
1435 {
1436   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1437   ErdreichAnbroeckeln(x, y);
1438 }
1439
1440 void DrawLevelElement(int x, int y, int element)
1441 {
1442   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1443     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1444 }
1445
1446 void DrawScreenField(int x, int y)
1447 {
1448   int ux = LEVELX(x), uy = LEVELY(y);
1449   int element;
1450
1451   if (!IN_LEV_FIELD(ux, uy))
1452   {
1453     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1454       element = EL_LEERRAUM;
1455     else
1456       element = BorderElement;
1457
1458     DrawScreenElement(x, y, element);
1459     return;
1460   }
1461
1462   element = Feld[ux][uy];
1463
1464   if (IS_MOVING(ux, uy))
1465   {
1466     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1467     boolean cut_mode = NO_CUTTING;
1468
1469     if (Store[ux][uy] == EL_MORAST_LEER ||
1470         Store[ux][uy] == EL_MAGIC_WALL_EMPTY ||
1471         Store[ux][uy] == EL_MAGIC_WALL_BD_EMPTY ||
1472         Store[ux][uy] == EL_AMOEBE_NASS)
1473       cut_mode = CUT_ABOVE;
1474     else if (Store[ux][uy] == EL_MORAST_VOLL ||
1475              Store[ux][uy] == EL_MAGIC_WALL_FULL ||
1476              Store[ux][uy] == EL_MAGIC_WALL_BD_FULL)
1477       cut_mode = CUT_BELOW;
1478
1479     if (cut_mode == CUT_ABOVE)
1480       DrawScreenElementShifted(x, y, 0, 0, Store[ux][uy], NO_CUTTING);
1481     else
1482       DrawScreenElement(x, y, EL_LEERRAUM);
1483
1484     if (horiz_move)
1485       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1486     else
1487       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1488
1489     if (Store[ux][uy] == EL_SALZSAEURE)
1490       DrawLevelElementThruMask(ux, uy + 1, EL_SALZSAEURE);
1491   }
1492   else if (IS_BLOCKED(ux, uy))
1493   {
1494     int oldx, oldy;
1495     int sx, sy;
1496     int horiz_move;
1497     boolean cut_mode = NO_CUTTING;
1498
1499     Blocked2Moving(ux, uy, &oldx, &oldy);
1500     sx = SCREENX(oldx);
1501     sy = SCREENY(oldy);
1502     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1503                   MovDir[oldx][oldy] == MV_RIGHT);
1504
1505     if (Store[oldx][oldy] == EL_MORAST_LEER ||
1506         Store[oldx][oldy] == EL_MAGIC_WALL_EMPTY ||
1507         Store[oldx][oldy] == EL_MAGIC_WALL_BD_EMPTY ||
1508         Store[oldx][oldy] == EL_AMOEBE_NASS)
1509       cut_mode = CUT_ABOVE;
1510
1511     DrawScreenElement(x, y, EL_LEERRAUM);
1512     element = Feld[oldx][oldy];
1513
1514     if (horiz_move)
1515       DrawScreenElementShifted(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
1516     else
1517       DrawScreenElementShifted(sx,sy, 0,MovPos[oldx][oldy],element,cut_mode);
1518   }
1519   else if (IS_DRAWABLE(element))
1520     DrawScreenElement(x, y, element);
1521   else
1522     DrawScreenElement(x, y, EL_LEERRAUM);
1523 }
1524
1525 void DrawLevelField(int x, int y)
1526 {
1527   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1528     DrawScreenField(SCREENX(x), SCREENY(y));
1529   else if (IS_MOVING(x, y))
1530   {
1531     int newx,newy;
1532
1533     Moving2Blocked(x, y, &newx, &newy);
1534     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1535       DrawScreenField(SCREENX(newx), SCREENY(newy));
1536   }
1537   else if (IS_BLOCKED(x, y))
1538   {
1539     int oldx, oldy;
1540
1541     Blocked2Moving(x, y, &oldx, &oldy);
1542     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1543       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1544   }
1545 }
1546
1547 void DrawMiniElement(int x, int y, int element)
1548 {
1549   int graphic;
1550
1551   if (!element)
1552   {
1553     DrawMiniGraphic(x, y, -1);
1554     return;
1555   }
1556
1557   graphic = el2gfx(element);
1558   DrawMiniGraphic(x, y, graphic);
1559 }
1560
1561 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1562 {
1563   int x = sx + scroll_x, y = sy + scroll_y;
1564
1565   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1566     DrawMiniElement(sx, sy, EL_LEERRAUM);
1567   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1568     DrawMiniElement(sx, sy, Feld[x][y]);
1569   else
1570   {
1571     int steel_type, steel_position;
1572     int border[6][2] =
1573     {
1574       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
1575       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
1576       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
1577       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
1578       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
1579       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
1580     };
1581
1582     steel_type = (BorderElement == EL_BETON ? 0 : 1);
1583     steel_position = (x == -1 && y == -1                        ? 0 :
1584                       x == lev_fieldx && y == -1                ? 1 :
1585                       x == -1 && y == lev_fieldy                ? 2 :
1586                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1587                       x == -1 || x == lev_fieldx                ? 4 :
1588                       y == -1 || y == lev_fieldy                ? 5 : -1);
1589
1590     if (steel_position != -1)
1591       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1592   }
1593 }
1594
1595 void DrawMicroElement(int xpos, int ypos, int element)
1596 {
1597   int graphic;
1598
1599   if (element == EL_LEERRAUM)
1600     return;
1601
1602   graphic = el2gfx(element);
1603
1604   if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1605   {
1606     graphic -= GFX_START_ROCKSSP;
1607     graphic -= ((graphic / SP_PER_LINE) * SP_PER_LINE) / 2;
1608     BlitBitmap(pix[PIX_SP], drawto,
1609                MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
1610                MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
1611                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1612   }
1613   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1614   {
1615     graphic -= GFX_START_ROCKSDC;
1616     BlitBitmap(pix[PIX_DC], drawto,
1617                MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
1618                MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
1619                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1620   }
1621   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1622   {
1623     graphic -= GFX_START_ROCKSMORE;
1624     BlitBitmap(pix[PIX_MORE], drawto,
1625                MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE)*MICRO_TILEX,
1626                MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE)*MICRO_TILEY,
1627                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1628   }
1629   else
1630     BlitBitmap(pix[PIX_BACK], drawto,
1631                MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
1632                MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
1633                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
1634 }
1635
1636 void DrawLevel()
1637 {
1638   int x,y;
1639
1640   ClearWindow();
1641
1642   for(x=BX1; x<=BX2; x++)
1643     for(y=BY1; y<=BY2; y++)
1644       DrawScreenField(x, y);
1645
1646   redraw_mask |= REDRAW_FIELD;
1647 }
1648
1649 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1650 {
1651   int x,y;
1652
1653   for(x=0; x<size_x; x++)
1654     for(y=0; y<size_y; y++)
1655       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1656
1657   redraw_mask |= REDRAW_FIELD;
1658 }
1659
1660 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1661 {
1662   int x, y;
1663
1664   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1665
1666   if (lev_fieldx < STD_LEV_FIELDX)
1667     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1668   if (lev_fieldy < STD_LEV_FIELDY)
1669     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1670
1671   xpos += MICRO_TILEX;
1672   ypos += MICRO_TILEY;
1673
1674   for(x=-1; x<=STD_LEV_FIELDX; x++)
1675   {
1676     for(y=-1; y<=STD_LEV_FIELDY; y++)
1677     {
1678       int lx = from_x + x, ly = from_y + y;
1679
1680       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1681         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1682                          Ur[lx][ly]);
1683       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1684         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1685                          BorderElement);
1686     }
1687   }
1688
1689   redraw_mask |= REDRAW_MICROLEVEL;
1690 }
1691
1692 #define MICROLABEL_EMPTY                0
1693 #define MICROLABEL_LEVEL_NAME           1
1694 #define MICROLABEL_CREATED_BY           2
1695 #define MICROLABEL_LEVEL_AUTHOR         3
1696 #define MICROLABEL_IMPORTED_FROM        4
1697 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1698
1699 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1700
1701 static void DrawMicroLevelLabelExt(int mode)
1702 {
1703   char label_text[MAX_MICROLABEL_SIZE + 1];
1704
1705   ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1706
1707   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1708                        mode == MICROLABEL_CREATED_BY ? "created by" :
1709                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1710                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1711                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1712                        leveldir_current->imported_from : ""),
1713           MAX_MICROLABEL_SIZE);
1714   label_text[MAX_MICROLABEL_SIZE] = '\0';
1715
1716   if (strlen(label_text) > 0)
1717   {
1718     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1719     int lypos = MICROLABEL_YPOS;
1720
1721     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1722   }
1723
1724   redraw_mask |= REDRAW_MICROLEVEL;
1725 }
1726
1727 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1728 {
1729   static unsigned long scroll_delay = 0;
1730   static unsigned long label_delay = 0;
1731   static int from_x, from_y, scroll_direction;
1732   static int label_state, label_counter;
1733
1734   if (restart)
1735   {
1736     from_x = from_y = 0;
1737     scroll_direction = MV_RIGHT;
1738     label_state = 1;
1739     label_counter = 0;
1740
1741     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1742     DrawMicroLevelLabelExt(label_state);
1743
1744     /* initialize delay counters */
1745     DelayReached(&scroll_delay, 0);
1746     DelayReached(&label_delay, 0);
1747
1748     return;
1749   }
1750
1751   /* scroll micro level, if needed */
1752   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1753       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1754   {
1755     switch (scroll_direction)
1756     {
1757       case MV_LEFT:
1758         if (from_x > 0)
1759           from_x--;
1760         else
1761           scroll_direction = MV_UP;
1762         break;
1763
1764       case MV_RIGHT:
1765         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1766           from_x++;
1767         else
1768           scroll_direction = MV_DOWN;
1769         break;
1770
1771       case MV_UP:
1772         if (from_y > 0)
1773           from_y--;
1774         else
1775           scroll_direction = MV_RIGHT;
1776         break;
1777
1778       case MV_DOWN:
1779         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1780           from_y++;
1781         else
1782           scroll_direction = MV_LEFT;
1783         break;
1784
1785       default:
1786         break;
1787     }
1788
1789     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1790   }
1791
1792   /* redraw micro level label, if needed */
1793   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1794       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1795       strcmp(level.author, leveldir_current->name) != 0 &&
1796       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1797   {
1798     int max_label_counter = 23;
1799
1800     if (leveldir_current->imported_from != NULL)
1801       max_label_counter += 14;
1802
1803     label_counter = (label_counter + 1) % max_label_counter;
1804     label_state = (label_counter >= 0 && label_counter <= 7 ?
1805                    MICROLABEL_LEVEL_NAME :
1806                    label_counter >= 9 && label_counter <= 12 ?
1807                    MICROLABEL_CREATED_BY :
1808                    label_counter >= 14 && label_counter <= 21 ?
1809                    MICROLABEL_LEVEL_AUTHOR :
1810                    label_counter >= 23 && label_counter <= 26 ?
1811                    MICROLABEL_IMPORTED_FROM :
1812                    label_counter >= 28 && label_counter <= 35 ?
1813                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1814     DrawMicroLevelLabelExt(label_state);
1815   }
1816 }
1817
1818 int REQ_in_range(int x, int y)
1819 {
1820   if (y > DY+249 && y < DY+278)
1821   {
1822     if (x > DX+1 && x < DX+48)
1823       return 1;
1824     else if (x > DX+51 && x < DX+98) 
1825       return 2;
1826   }
1827   return 0;
1828 }
1829
1830 boolean Request(char *text, unsigned int req_state)
1831 {
1832   int mx, my, ty, result = -1;
1833   unsigned int old_door_state;
1834
1835 #if defined(PLATFORM_UNIX)
1836   /* pause network game while waiting for request to answer */
1837   if (options.network &&
1838       game_status == PLAYING &&
1839       req_state & REQUEST_WAIT_FOR)
1840     SendToServer_PausePlaying();
1841 #endif
1842
1843   old_door_state = GetDoorState();
1844
1845   UnmapAllGadgets();
1846
1847   CloseDoor(DOOR_CLOSE_1);
1848
1849   /* save old door content */
1850   BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1851              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1852              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1853
1854   /* clear door drawing field */
1855   ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1856
1857   /* write text for request */
1858   for(ty=0; ty<13; ty++)
1859   {
1860     int tx, tl, tc;
1861     char txt[256];
1862
1863     if (!*text)
1864       break;
1865
1866     for(tl=0,tx=0; tx<7; tl++,tx++)
1867     {
1868       tc = *(text + tx);
1869       if (!tc || tc == 32)
1870         break;
1871     }
1872     if (!tl)
1873     { 
1874       text++; 
1875       ty--; 
1876       continue; 
1877     }
1878     sprintf(txt, text); 
1879     txt[tl] = 0;
1880     DrawTextExt(drawto, DX + 51 - (tl * 14)/2, DY + 8 + ty * 16,
1881                 txt, FS_SMALL, FC_YELLOW);
1882     text += tl + (tc == 32 ? 1 : 0);
1883   }
1884
1885   if (req_state & REQ_ASK)
1886   {
1887     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1888     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1889   }
1890   else if (req_state & REQ_CONFIRM)
1891   {
1892     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1893   }
1894   else if (req_state & REQ_PLAYER)
1895   {
1896     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1897     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1898     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1899     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1900   }
1901
1902   /* copy request gadgets to door backbuffer */
1903   BlitBitmap(drawto, pix[PIX_DB_DOOR],
1904              DX, DY, DXSIZE, DYSIZE,
1905              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1906
1907   OpenDoor(DOOR_OPEN_1);
1908
1909 #if 0
1910   ClearEventQueue();
1911 #endif
1912
1913   if (!(req_state & REQUEST_WAIT_FOR))
1914     return(FALSE);
1915
1916   if (game_status != MAINMENU)
1917     InitAnimation();
1918
1919   button_status = MB_RELEASED;
1920
1921   request_gadget_id = -1;
1922
1923   while(result < 0)
1924   {
1925     if (PendingEvent())
1926     {
1927       Event event;
1928
1929       NextEvent(&event);
1930
1931       switch(event.type)
1932       {
1933         case EVENT_BUTTONPRESS:
1934         case EVENT_BUTTONRELEASE:
1935         case EVENT_MOTIONNOTIFY:
1936         {
1937           if (event.type == EVENT_MOTIONNOTIFY)
1938           {
1939             if (!PointerInWindow(window))
1940               continue; /* window and pointer are on different screens */
1941
1942             if (!button_status)
1943               continue;
1944
1945             motion_status = TRUE;
1946             mx = ((MotionEvent *) &event)->x;
1947             my = ((MotionEvent *) &event)->y;
1948           }
1949           else
1950           {
1951             motion_status = FALSE;
1952             mx = ((ButtonEvent *) &event)->x;
1953             my = ((ButtonEvent *) &event)->y;
1954             if (event.type == EVENT_BUTTONPRESS)
1955               button_status = ((ButtonEvent *) &event)->button;
1956             else
1957               button_status = MB_RELEASED;
1958           }
1959
1960           /* this sets 'request_gadget_id' */
1961           HandleGadgets(mx, my, button_status);
1962
1963           switch(request_gadget_id)
1964           {
1965             case TOOL_CTRL_ID_YES:
1966               result = TRUE;
1967               break;
1968             case TOOL_CTRL_ID_NO:
1969               result = FALSE;
1970               break;
1971             case TOOL_CTRL_ID_CONFIRM:
1972               result = TRUE | FALSE;
1973               break;
1974
1975             case TOOL_CTRL_ID_PLAYER_1:
1976               result = 1;
1977               break;
1978             case TOOL_CTRL_ID_PLAYER_2:
1979               result = 2;
1980               break;
1981             case TOOL_CTRL_ID_PLAYER_3:
1982               result = 3;
1983               break;
1984             case TOOL_CTRL_ID_PLAYER_4:
1985               result = 4;
1986               break;
1987
1988             default:
1989               break;
1990           }
1991
1992           break;
1993         }
1994
1995         case EVENT_KEYPRESS:
1996           switch(GetEventKey((KeyEvent *)&event, TRUE))
1997           {
1998             case KSYM_Return:
1999               result = 1;
2000               break;
2001
2002             case KSYM_Escape:
2003               result = 0;
2004               break;
2005
2006             default:
2007               break;
2008           }
2009           if (req_state & REQ_PLAYER)
2010             result = 0;
2011           break;
2012
2013         case EVENT_KEYRELEASE:
2014           key_joystick_mapping = 0;
2015           break;
2016
2017         default:
2018           HandleOtherEvents(&event);
2019           break;
2020       }
2021     }
2022     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2023     {
2024       int joy = AnyJoystick();
2025
2026       if (joy & JOY_BUTTON_1)
2027         result = 1;
2028       else if (joy & JOY_BUTTON_2)
2029         result = 0;
2030     }
2031
2032     DoAnimation();
2033
2034     /* don't eat all CPU time */
2035     Delay(10);
2036   }
2037
2038   if (game_status != MAINMENU)
2039     StopAnimation();
2040
2041   UnmapToolButtons();
2042
2043   if (!(req_state & REQ_STAY_OPEN))
2044   {
2045     CloseDoor(DOOR_CLOSE_1);
2046
2047     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2048     {
2049       BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2050                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2051                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2052       OpenDoor(DOOR_OPEN_1);
2053     }
2054   }
2055
2056   RemapAllGadgets();
2057
2058 #if defined(PLATFORM_UNIX)
2059   /* continue network game after request */
2060   if (options.network &&
2061       game_status == PLAYING &&
2062       req_state & REQUEST_WAIT_FOR)
2063     SendToServer_ContinuePlaying();
2064 #endif
2065
2066   return(result);
2067 }
2068
2069 unsigned int OpenDoor(unsigned int door_state)
2070 {
2071   unsigned int new_door_state;
2072
2073   if (door_state & DOOR_COPY_BACK)
2074   {
2075     BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2076                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2077                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2078     door_state &= ~DOOR_COPY_BACK;
2079   }
2080
2081   new_door_state = MoveDoor(door_state);
2082
2083   return(new_door_state);
2084 }
2085
2086 unsigned int CloseDoor(unsigned int door_state)
2087 {
2088   unsigned int new_door_state;
2089
2090   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2091              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2092   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2093              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2094
2095   new_door_state = MoveDoor(door_state);
2096
2097   return(new_door_state);
2098 }
2099
2100 unsigned int GetDoorState()
2101 {
2102   return(MoveDoor(DOOR_GET_STATE));
2103 }
2104
2105 unsigned int MoveDoor(unsigned int door_state)
2106 {
2107   static int door1 = DOOR_OPEN_1;
2108   static int door2 = DOOR_CLOSE_2;
2109   static unsigned long door_delay = 0;
2110   int x, start, stepsize = 2;
2111   unsigned long door_delay_value = stepsize * 5;
2112
2113   if (door_state == DOOR_GET_STATE)
2114     return(door1 | door2);
2115
2116   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2117     door_state &= ~DOOR_OPEN_1;
2118   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2119     door_state &= ~DOOR_CLOSE_1;
2120   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2121     door_state &= ~DOOR_OPEN_2;
2122   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2123     door_state &= ~DOOR_CLOSE_2;
2124
2125   if (setup.quick_doors)
2126   {
2127     stepsize = 20;
2128     door_delay_value = 0;
2129     StopSound(SND_OEFFNEN);
2130   }
2131
2132   if (door_state & DOOR_ACTION)
2133   {
2134     if (!(door_state & DOOR_NO_DELAY))
2135       PlaySoundStereo(SND_OEFFNEN, PSND_MAX_RIGHT);
2136
2137     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2138
2139     for(x=start; x<=DXSIZE; x+=stepsize)
2140     {
2141       Bitmap bitmap = pix[PIX_DOOR];
2142       GC gc = bitmap->stored_clip_gc;
2143
2144       WaitUntilDelayReached(&door_delay, door_delay_value);
2145
2146       if (door_state & DOOR_ACTION_1)
2147       {
2148         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2149         int j = (DXSIZE - i) / 3;
2150
2151         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2152                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2153                    DXSIZE,DYSIZE - i/2, DX, DY);
2154
2155         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2156
2157         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2158         BlitBitmapMasked(bitmap, drawto,
2159                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2160                          DX + DXSIZE - i, DY + j);
2161         BlitBitmapMasked(bitmap, drawto,
2162                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2163                          DX + DXSIZE - i, DY + 140 + j);
2164         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2165         BlitBitmapMasked(bitmap, drawto,
2166                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2167                          DX, DY);
2168         BlitBitmapMasked(bitmap, drawto,
2169                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2170                          DX, DY + 140 - j);
2171
2172         BlitBitmapMasked(bitmap, drawto,
2173                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2174                          DX, DY + 77 - j);
2175         BlitBitmapMasked(bitmap, drawto,
2176                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2177                          DX, DY + 203 - j);
2178         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2179         BlitBitmapMasked(bitmap, drawto,
2180                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2181                          DX + DXSIZE - i, DY + 77 + j);
2182         BlitBitmapMasked(bitmap, drawto,
2183                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2184                          DX + DXSIZE - i, DY + 203 + j);
2185
2186         redraw_mask |= REDRAW_DOOR_1;
2187       }
2188
2189       if (door_state & DOOR_ACTION_2)
2190       {
2191         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2192         int j = (VXSIZE - i) / 3;
2193
2194         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2195                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2196                    VXSIZE, VYSIZE - i/2, VX, VY);
2197
2198         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2199
2200         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2201         BlitBitmapMasked(bitmap, drawto,
2202                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2203                          VX + VXSIZE-i, VY+j);
2204         SetClipOrigin(bitmap, gc,
2205                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2206         BlitBitmapMasked(bitmap, drawto,
2207                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2208                          VX, VY);
2209
2210         BlitBitmapMasked(bitmap, drawto,
2211                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2212                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2213         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2214         BlitBitmapMasked(bitmap, drawto,
2215                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2216                          i, VYSIZE / 2 - j,
2217                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2218
2219         redraw_mask |= REDRAW_DOOR_2;
2220       }
2221
2222       BackToFront();
2223
2224       if (game_status == MAINMENU)
2225         DoAnimation();
2226     }
2227   }
2228
2229   if (setup.quick_doors)
2230     StopSound(SND_OEFFNEN);
2231
2232   if (door_state & DOOR_ACTION_1)
2233     door1 = door_state & DOOR_ACTION_1;
2234   if (door_state & DOOR_ACTION_2)
2235     door2 = door_state & DOOR_ACTION_2;
2236
2237   return (door1 | door2);
2238 }
2239
2240 void DrawSpecialEditorDoor()
2241 {
2242   /* draw bigger toolbox window */
2243   BlitBitmap(pix[PIX_DOOR], drawto,
2244              DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2245
2246   redraw_mask |= REDRAW_ALL;
2247 }
2248
2249 void UndrawSpecialEditorDoor()
2250 {
2251   /* draw normal tape recorder window */
2252   BlitBitmap(pix[PIX_BACK], drawto,
2253              562, 344, 108, 56, EX - 4, EY - 12);
2254
2255   redraw_mask |= REDRAW_ALL;
2256 }
2257
2258 #ifndef TARGET_SDL
2259 int ReadPixel(DrawBuffer bitmap, int x, int y)
2260 {
2261   XImage *pixel_image;
2262   unsigned long pixel_value;
2263
2264   pixel_image = XGetImage(display, bitmap->drawable,
2265                           x, y, 1, 1, AllPlanes, ZPixmap);
2266   pixel_value = XGetPixel(pixel_image, 0, 0);
2267
2268   XDestroyImage(pixel_image);
2269
2270   return pixel_value;
2271 }
2272 #endif
2273
2274 /* ---------- new tool button stuff ---------------------------------------- */
2275
2276 /* graphic position values for tool buttons */
2277 #define TOOL_BUTTON_YES_XPOS            2
2278 #define TOOL_BUTTON_YES_YPOS            250
2279 #define TOOL_BUTTON_YES_GFX_YPOS        0
2280 #define TOOL_BUTTON_YES_XSIZE           46
2281 #define TOOL_BUTTON_YES_YSIZE           28
2282 #define TOOL_BUTTON_NO_XPOS             52
2283 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2284 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2285 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2286 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2287 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2288 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2289 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2290 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2291 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2292 #define TOOL_BUTTON_PLAYER_XSIZE        30
2293 #define TOOL_BUTTON_PLAYER_YSIZE        30
2294 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2295 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2296 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2297 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2298 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2299                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2300 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2301                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2302 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2303                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2304 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2305                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2306 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2307                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2308 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2309                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2310 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2311                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2312 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2313                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2314
2315 static struct
2316 {
2317   int xpos, ypos;
2318   int x, y;
2319   int width, height;
2320   int gadget_id;
2321   char *infotext;
2322 } toolbutton_info[NUM_TOOL_BUTTONS] =
2323 {
2324   {
2325     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2326     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2327     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2328     TOOL_CTRL_ID_YES,
2329     "yes"
2330   },
2331   {
2332     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2333     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2334     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2335     TOOL_CTRL_ID_NO,
2336     "no"
2337   },
2338   {
2339     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2340     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2341     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2342     TOOL_CTRL_ID_CONFIRM,
2343     "confirm"
2344   },
2345   {
2346     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2347     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2348     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2349     TOOL_CTRL_ID_PLAYER_1,
2350     "player 1"
2351   },
2352   {
2353     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2354     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2355     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2356     TOOL_CTRL_ID_PLAYER_2,
2357     "player 2"
2358   },
2359   {
2360     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2361     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2362     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2363     TOOL_CTRL_ID_PLAYER_3,
2364     "player 3"
2365   },
2366   {
2367     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2368     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2369     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2370     TOOL_CTRL_ID_PLAYER_4,
2371     "player 4"
2372   }
2373 };
2374
2375 #if 0
2376 static void DoNotDisplayInfoText(void *ptr)
2377 {
2378   return;
2379 }
2380 #endif
2381
2382 void CreateToolButtons()
2383 {
2384   int i;
2385
2386   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2387   {
2388     Bitmap gd_bitmap = pix[PIX_DOOR];
2389     Bitmap deco_bitmap = None;
2390     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2391     struct GadgetInfo *gi;
2392     unsigned long event_mask;
2393     int gd_xoffset, gd_yoffset;
2394     int gd_x1, gd_x2, gd_y;
2395     int id = i;
2396
2397     event_mask = GD_EVENT_RELEASED;
2398
2399     gd_xoffset = toolbutton_info[i].xpos;
2400     gd_yoffset = toolbutton_info[i].ypos;
2401     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2402     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2403     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2404
2405     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2406     {
2407       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
2408                            &deco_bitmap, &deco_x, &deco_y);
2409       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2410       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2411     }
2412
2413     gi = CreateGadget(GDI_CUSTOM_ID, id,
2414                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2415                       GDI_X, DX + toolbutton_info[i].x,
2416                       GDI_Y, DY + toolbutton_info[i].y,
2417                       GDI_WIDTH, toolbutton_info[i].width,
2418                       GDI_HEIGHT, toolbutton_info[i].height,
2419                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2420                       GDI_STATE, GD_BUTTON_UNPRESSED,
2421                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2422                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2423                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2424                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2425                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2426                       GDI_DECORATION_SHIFTING, 1, 1,
2427                       GDI_EVENT_MASK, event_mask,
2428
2429 #if 0
2430                       GDI_CALLBACK_INFO, DoNotDisplayInfoText,
2431 #endif
2432
2433                       GDI_CALLBACK_ACTION, HandleToolButtons,
2434                       GDI_END);
2435
2436     if (gi == NULL)
2437       Error(ERR_EXIT, "cannot create gadget");
2438
2439     tool_gadget[id] = gi;
2440   }
2441 }
2442
2443 static void UnmapToolButtons()
2444 {
2445   int i;
2446
2447   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2448     UnmapGadget(tool_gadget[i]);
2449 }
2450
2451 static void HandleToolButtons(struct GadgetInfo *gi)
2452 {
2453   request_gadget_id = gi->custom_id;
2454 }
2455
2456 int el2gfx(int element)
2457 {
2458   switch(element)
2459   {
2460     case EL_LEERRAUM:           return -1;
2461     case EL_ERDREICH:           return GFX_ERDREICH;
2462     case EL_MAUERWERK:          return GFX_MAUERWERK;
2463     case EL_FELSBODEN:          return GFX_FELSBODEN;
2464     case EL_FELSBROCKEN:        return GFX_FELSBROCKEN;
2465     case EL_SCHLUESSEL:         return GFX_SCHLUESSEL;
2466     case EL_EDELSTEIN:          return GFX_EDELSTEIN;
2467     case EL_AUSGANG_ZU:         return GFX_AUSGANG_ZU;
2468     case EL_AUSGANG_ACT:        return GFX_AUSGANG_ACT;
2469     case EL_AUSGANG_AUF:        return GFX_AUSGANG_AUF;
2470     case EL_SPIELFIGUR:         return GFX_SPIELFIGUR;
2471     case EL_SPIELER1:           return GFX_SPIELER1;
2472     case EL_SPIELER2:           return GFX_SPIELER2;
2473     case EL_SPIELER3:           return GFX_SPIELER3;
2474     case EL_SPIELER4:           return GFX_SPIELER4;
2475     case EL_KAEFER:             return GFX_KAEFER;
2476     case EL_KAEFER_RIGHT:       return GFX_KAEFER_RIGHT;
2477     case EL_KAEFER_UP:          return GFX_KAEFER_UP;
2478     case EL_KAEFER_LEFT:        return GFX_KAEFER_LEFT;
2479     case EL_KAEFER_DOWN:        return GFX_KAEFER_DOWN;
2480     case EL_FLIEGER:            return GFX_FLIEGER;
2481     case EL_FLIEGER_RIGHT:      return GFX_FLIEGER_RIGHT;
2482     case EL_FLIEGER_UP:         return GFX_FLIEGER_UP;
2483     case EL_FLIEGER_LEFT:       return GFX_FLIEGER_LEFT;
2484     case EL_FLIEGER_DOWN:       return GFX_FLIEGER_DOWN;
2485     case EL_BUTTERFLY:          return GFX_BUTTERFLY;
2486     case EL_BUTTERFLY_RIGHT:    return GFX_BUTTERFLY_RIGHT;
2487     case EL_BUTTERFLY_UP:       return GFX_BUTTERFLY_UP;
2488     case EL_BUTTERFLY_LEFT:     return GFX_BUTTERFLY_LEFT;
2489     case EL_BUTTERFLY_DOWN:     return GFX_BUTTERFLY_DOWN;
2490     case EL_FIREFLY:            return GFX_FIREFLY;
2491     case EL_FIREFLY_RIGHT:      return GFX_FIREFLY_RIGHT;
2492     case EL_FIREFLY_UP:         return GFX_FIREFLY_UP;
2493     case EL_FIREFLY_LEFT:       return GFX_FIREFLY_LEFT;
2494     case EL_FIREFLY_DOWN:       return GFX_FIREFLY_DOWN;
2495     case EL_MAMPFER:            return GFX_MAMPFER;
2496     case EL_ROBOT:              return GFX_ROBOT;
2497     case EL_BETON:              return GFX_BETON;
2498     case EL_DIAMANT:            return GFX_DIAMANT;
2499     case EL_MORAST_LEER:        return GFX_MORAST_LEER;
2500     case EL_MORAST_VOLL:        return GFX_MORAST_VOLL;
2501     case EL_TROPFEN:            return GFX_TROPFEN;
2502     case EL_BOMBE:              return GFX_BOMBE;
2503     case EL_MAGIC_WALL_OFF:     return GFX_MAGIC_WALL_OFF;
2504     case EL_MAGIC_WALL_EMPTY:   return GFX_MAGIC_WALL_EMPTY;
2505     case EL_MAGIC_WALL_FULL:    return GFX_MAGIC_WALL_FULL;
2506     case EL_MAGIC_WALL_DEAD:    return GFX_MAGIC_WALL_DEAD;
2507     case EL_SALZSAEURE:         return GFX_SALZSAEURE;
2508     case EL_AMOEBE_TOT:         return GFX_AMOEBE_TOT;
2509     case EL_AMOEBE_NASS:        return GFX_AMOEBE_NASS;
2510     case EL_AMOEBE_NORM:        return GFX_AMOEBE_NORM;
2511     case EL_AMOEBE_VOLL:        return GFX_AMOEBE_VOLL;
2512     case EL_AMOEBE_BD:          return GFX_AMOEBE_BD;
2513     case EL_AMOEBA2DIAM:        return GFX_AMOEBA2DIAM;
2514     case EL_KOKOSNUSS:          return GFX_KOKOSNUSS;
2515     case EL_LIFE:               return GFX_LIFE;
2516     case EL_LIFE_ASYNC:         return GFX_LIFE_ASYNC;
2517     case EL_DYNAMITE_ACTIVE:    return GFX_DYNAMIT;
2518     case EL_BADEWANNE:          return GFX_BADEWANNE;
2519     case EL_BADEWANNE1:         return GFX_BADEWANNE1;
2520     case EL_BADEWANNE2:         return GFX_BADEWANNE2;
2521     case EL_BADEWANNE3:         return GFX_BADEWANNE3;
2522     case EL_BADEWANNE4:         return GFX_BADEWANNE4;
2523     case EL_BADEWANNE5:         return GFX_BADEWANNE5;
2524     case EL_ABLENK_AUS:         return GFX_ABLENK_AUS;
2525     case EL_ABLENK_EIN:         return GFX_ABLENK_EIN;
2526     case EL_SCHLUESSEL1:        return GFX_SCHLUESSEL1;
2527     case EL_SCHLUESSEL2:        return GFX_SCHLUESSEL2;
2528     case EL_SCHLUESSEL3:        return GFX_SCHLUESSEL3;
2529     case EL_SCHLUESSEL4:        return GFX_SCHLUESSEL4;
2530     case EL_PFORTE1:            return GFX_PFORTE1;
2531     case EL_PFORTE2:            return GFX_PFORTE2;
2532     case EL_PFORTE3:            return GFX_PFORTE3;
2533     case EL_PFORTE4:            return GFX_PFORTE4;
2534     case EL_PFORTE1X:           return GFX_PFORTE1X;
2535     case EL_PFORTE2X:           return GFX_PFORTE2X;
2536     case EL_PFORTE3X:           return GFX_PFORTE3X;
2537     case EL_PFORTE4X:           return GFX_PFORTE4X;
2538     case EL_DYNAMITE_INACTIVE:  return GFX_DYNAMIT_AUS;
2539     case EL_PACMAN:             return GFX_PACMAN;
2540     case EL_PACMAN_RIGHT:       return GFX_PACMAN_RIGHT;
2541     case EL_PACMAN_UP:          return GFX_PACMAN_UP;
2542     case EL_PACMAN_LEFT:        return GFX_PACMAN_LEFT;
2543     case EL_PACMAN_DOWN:        return GFX_PACMAN_DOWN;
2544     case EL_UNSICHTBAR:         return GFX_UNSICHTBAR;
2545     case EL_ERZ_EDEL:           return GFX_ERZ_EDEL;
2546     case EL_ERZ_DIAM:           return GFX_ERZ_DIAM;
2547     case EL_BIRNE_AUS:          return GFX_BIRNE_AUS;
2548     case EL_BIRNE_EIN:          return GFX_BIRNE_EIN;
2549     case EL_ZEIT_VOLL:          return GFX_ZEIT_VOLL;
2550     case EL_ZEIT_LEER:          return GFX_ZEIT_LEER;
2551     case EL_MAUER_LEBT:         return GFX_MAUER_LEBT;
2552     case EL_MAUER_X:            return GFX_MAUER_X;
2553     case EL_MAUER_Y:            return GFX_MAUER_Y;
2554     case EL_MAUER_XY:           return GFX_MAUER_XY;
2555     case EL_EDELSTEIN_BD:       return GFX_EDELSTEIN_BD;
2556     case EL_EDELSTEIN_GELB:     return GFX_EDELSTEIN_GELB;
2557     case EL_EDELSTEIN_ROT:      return GFX_EDELSTEIN_ROT;
2558     case EL_EDELSTEIN_LILA:     return GFX_EDELSTEIN_LILA;
2559     case EL_ERZ_EDEL_BD:        return GFX_ERZ_EDEL_BD;
2560     case EL_ERZ_EDEL_GELB:      return GFX_ERZ_EDEL_GELB;
2561     case EL_ERZ_EDEL_ROT:       return GFX_ERZ_EDEL_ROT;
2562     case EL_ERZ_EDEL_LILA:      return GFX_ERZ_EDEL_LILA;
2563     case EL_MAMPFER2:           return GFX_MAMPFER2;
2564     case EL_MAGIC_WALL_BD_OFF:  return GFX_MAGIC_WALL_BD_OFF;
2565     case EL_MAGIC_WALL_BD_EMPTY:return GFX_MAGIC_WALL_BD_EMPTY;
2566     case EL_MAGIC_WALL_BD_FULL: return GFX_MAGIC_WALL_BD_FULL;
2567     case EL_MAGIC_WALL_BD_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2568     case EL_DYNABOMB_ACTIVE_1:  return GFX_DYNABOMB;
2569     case EL_DYNABOMB_ACTIVE_2:  return GFX_DYNABOMB;
2570     case EL_DYNABOMB_ACTIVE_3:  return GFX_DYNABOMB;
2571     case EL_DYNABOMB_ACTIVE_4:  return GFX_DYNABOMB;
2572     case EL_DYNABOMB_NR:        return GFX_DYNABOMB_NR;
2573     case EL_DYNABOMB_SZ:        return GFX_DYNABOMB_SZ;
2574     case EL_DYNABOMB_XL:        return GFX_DYNABOMB_XL;
2575     case EL_SOKOBAN_OBJEKT:     return GFX_SOKOBAN_OBJEKT;
2576     case EL_SOKOBAN_FELD_LEER:  return GFX_SOKOBAN_FELD_LEER;
2577     case EL_SOKOBAN_FELD_VOLL:  return GFX_SOKOBAN_FELD_VOLL;
2578     case EL_MOLE:               return GFX_MOLE;
2579     case EL_PINGUIN:            return GFX_PINGUIN;
2580     case EL_SCHWEIN:            return GFX_SCHWEIN;
2581     case EL_DRACHE:             return GFX_DRACHE;
2582     case EL_SONDE:              return GFX_SONDE;
2583     case EL_PFEIL_LEFT:         return GFX_PFEIL_LEFT;
2584     case EL_PFEIL_RIGHT:        return GFX_PFEIL_RIGHT;
2585     case EL_PFEIL_UP:           return GFX_PFEIL_UP;
2586     case EL_PFEIL_DOWN:         return GFX_PFEIL_DOWN;
2587     case EL_SPEED_PILL:         return GFX_SPEED_PILL;
2588     case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2589     case EL_SP_BUG_ACTIVE:      return GFX_SP_BUG_ACTIVE;
2590     case EL_SP_ZONK:            return GFX_SP_ZONK;
2591       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2592     case EL_INVISIBLE_STEEL:    return GFX_INVISIBLE_STEEL;
2593     case EL_BLACK_ORB:          return GFX_BLACK_ORB;
2594     case EL_EM_GATE_1:          return GFX_EM_GATE_1;
2595     case EL_EM_GATE_2:          return GFX_EM_GATE_2;
2596     case EL_EM_GATE_3:          return GFX_EM_GATE_3;
2597     case EL_EM_GATE_4:          return GFX_EM_GATE_4;
2598     case EL_EM_GATE_1X:         return GFX_EM_GATE_1X;
2599     case EL_EM_GATE_2X:         return GFX_EM_GATE_2X;
2600     case EL_EM_GATE_3X:         return GFX_EM_GATE_3X;
2601     case EL_EM_GATE_4X:         return GFX_EM_GATE_4X;
2602     case EL_EM_KEY_1_FILE:      return GFX_EM_KEY_1;
2603     case EL_EM_KEY_2_FILE:      return GFX_EM_KEY_2;
2604     case EL_EM_KEY_3_FILE:      return GFX_EM_KEY_3;
2605     case EL_EM_KEY_4_FILE:      return GFX_EM_KEY_4;
2606     case EL_EM_KEY_1:           return GFX_EM_KEY_1;
2607     case EL_EM_KEY_2:           return GFX_EM_KEY_2;
2608     case EL_EM_KEY_3:           return GFX_EM_KEY_3;
2609     case EL_EM_KEY_4:           return GFX_EM_KEY_4;
2610     case EL_PEARL:              return GFX_PEARL;
2611     case EL_CRYSTAL:            return GFX_CRYSTAL;
2612     case EL_WALL_PEARL:         return GFX_WALL_PEARL;
2613     case EL_WALL_CRYSTAL:       return GFX_WALL_CRYSTAL;
2614     case EL_DOOR_WHITE:         return GFX_DOOR_WHITE;
2615     case EL_DOOR_WHITE_GRAY:    return GFX_DOOR_WHITE_GRAY;
2616     case EL_KEY_WHITE:          return GFX_KEY_WHITE;
2617     case EL_SHIELD_PASSIVE:     return GFX_SHIELD_PASSIVE;
2618     case EL_SHIELD_ACTIVE:      return GFX_SHIELD_ACTIVE;
2619     case EL_EXTRA_TIME:         return GFX_EXTRA_TIME;
2620     case EL_SWITCHGATE_OPEN:    return GFX_SWITCHGATE_OPEN;
2621     case EL_SWITCHGATE_CLOSED:  return GFX_SWITCHGATE_CLOSED;
2622     case EL_SWITCHGATE_SWITCH_1:return GFX_SWITCHGATE_SWITCH_1;
2623     case EL_SWITCHGATE_SWITCH_2:return GFX_SWITCHGATE_SWITCH_2;
2624     case EL_BELT1_LEFT:         return GFX_BELT1_LEFT;
2625     case EL_BELT1_MIDDLE:       return GFX_BELT1_MIDDLE;
2626     case EL_BELT1_RIGHT:        return GFX_BELT1_RIGHT;
2627     case EL_BELT1_SWITCH_LEFT:  return GFX_BELT1_SWITCH_LEFT;
2628     case EL_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2629     case EL_BELT1_SWITCH_RIGHT: return GFX_BELT1_SWITCH_RIGHT;
2630     case EL_BELT2_LEFT:         return GFX_BELT2_LEFT;
2631     case EL_BELT2_MIDDLE:       return GFX_BELT2_MIDDLE;
2632     case EL_BELT2_RIGHT:        return GFX_BELT2_RIGHT;
2633     case EL_BELT2_SWITCH_LEFT:  return GFX_BELT2_SWITCH_LEFT;
2634     case EL_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2635     case EL_BELT2_SWITCH_RIGHT: return GFX_BELT2_SWITCH_RIGHT;
2636     case EL_BELT3_LEFT:         return GFX_BELT3_LEFT;
2637     case EL_BELT3_MIDDLE:       return GFX_BELT3_MIDDLE;
2638     case EL_BELT3_RIGHT:        return GFX_BELT3_RIGHT;
2639     case EL_BELT3_SWITCH_LEFT:  return GFX_BELT3_SWITCH_LEFT;
2640     case EL_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2641     case EL_BELT3_SWITCH_RIGHT: return GFX_BELT3_SWITCH_RIGHT;
2642     case EL_BELT4_LEFT:         return GFX_BELT4_LEFT;
2643     case EL_BELT4_MIDDLE:       return GFX_BELT4_MIDDLE;
2644     case EL_BELT4_RIGHT:        return GFX_BELT4_RIGHT;
2645     case EL_BELT4_SWITCH_LEFT:  return GFX_BELT4_SWITCH_LEFT;
2646     case EL_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2647     case EL_BELT4_SWITCH_RIGHT: return GFX_BELT4_SWITCH_RIGHT;
2648     case EL_LANDMINE:           return GFX_LANDMINE;
2649     case EL_ENVELOPE:           return GFX_ENVELOPE;
2650     case EL_LIGHT_SWITCH_OFF:   return GFX_LIGHT_SWITCH_OFF;
2651     case EL_LIGHT_SWITCH_ON:    return GFX_LIGHT_SWITCH_ON;
2652     case EL_SIGN_EXCLAMATION:   return GFX_SIGN_EXCLAMATION;
2653     case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2654     case EL_SIGN_STOP:          return GFX_SIGN_STOP;
2655     case EL_SIGN_WHEELCHAIR:    return GFX_SIGN_WHEELCHAIR;
2656     case EL_SIGN_PARKING:       return GFX_SIGN_PARKING;
2657     case EL_SIGN_ONEWAY:        return GFX_SIGN_ONEWAY;
2658     case EL_SIGN_HEART:         return GFX_SIGN_HEART;
2659     case EL_SIGN_TRIANGLE:      return GFX_SIGN_TRIANGLE;
2660     case EL_SIGN_ROUND:         return GFX_SIGN_ROUND;
2661     case EL_SIGN_EXIT:          return GFX_SIGN_EXIT;
2662     case EL_SIGN_YINYANG:       return GFX_SIGN_YINYANG;
2663     case EL_SIGN_OTHER:         return GFX_SIGN_OTHER;
2664     case EL_MOLE_LEFT:          return GFX_MOLE_LEFT;
2665     case EL_MOLE_RIGHT:         return GFX_MOLE_RIGHT;
2666     case EL_MOLE_UP:            return GFX_MOLE_UP;
2667     case EL_MOLE_DOWN:          return GFX_MOLE_DOWN;
2668     case EL_STEEL_SLANTED:      return GFX_STEEL_SLANTED;
2669     case EL_SAND_INVISIBLE:     return GFX_SAND_INVISIBLE;
2670     case EL_DX_UNKNOWN_15:      return GFX_DX_UNKNOWN_15;
2671     case EL_DX_UNKNOWN_42:      return GFX_DX_UNKNOWN_42;
2672     case EL_TIMEGATE_OPEN:      return GFX_TIMEGATE_OPEN;
2673     case EL_TIMEGATE_CLOSED:    return GFX_TIMEGATE_CLOSED;
2674     case EL_TIMEGATE_SWITCH_ON: return GFX_TIMEGATE_SWITCH;
2675     case EL_TIMEGATE_SWITCH_OFF:return GFX_TIMEGATE_SWITCH;
2676     case EL_BALLOON:            return GFX_BALLOON;
2677     case EL_BALLOON_SEND_LEFT:  return GFX_BALLOON_SEND_LEFT;
2678     case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2679     case EL_BALLOON_SEND_UP:    return GFX_BALLOON_SEND_UP;
2680     case EL_BALLOON_SEND_DOWN:  return GFX_BALLOON_SEND_DOWN;
2681     case EL_BALLOON_SEND_ANY:   return GFX_BALLOON_SEND_ANY;
2682     case EL_EMC_STEEL_WALL_1:   return GFX_EMC_STEEL_WALL_1;
2683     case EL_EMC_STEEL_WALL_2:   return GFX_EMC_STEEL_WALL_2;
2684     case EL_EMC_STEEL_WALL_3:   return GFX_EMC_STEEL_WALL_3;
2685     case EL_EMC_STEEL_WALL_4:   return GFX_EMC_STEEL_WALL_4;
2686     case EL_EMC_WALL_1:         return GFX_EMC_WALL_1;
2687     case EL_EMC_WALL_2:         return GFX_EMC_WALL_2;
2688     case EL_EMC_WALL_3:         return GFX_EMC_WALL_3;
2689     case EL_EMC_WALL_4:         return GFX_EMC_WALL_4;
2690     case EL_EMC_WALL_5:         return GFX_EMC_WALL_5;
2691     case EL_EMC_WALL_6:         return GFX_EMC_WALL_6;
2692     case EL_EMC_WALL_7:         return GFX_EMC_WALL_7;
2693     case EL_EMC_WALL_8:         return GFX_EMC_WALL_8;
2694     case EL_TUBE_CROSS:         return GFX_TUBE_CROSS;
2695     case EL_TUBE_VERTICAL:      return GFX_TUBE_VERTICAL;
2696     case EL_TUBE_HORIZONTAL:    return GFX_TUBE_HORIZONTAL;
2697     case EL_TUBE_VERT_LEFT:     return GFX_TUBE_VERT_LEFT;
2698     case EL_TUBE_VERT_RIGHT:    return GFX_TUBE_VERT_RIGHT;
2699     case EL_TUBE_HORIZ_UP:      return GFX_TUBE_HORIZ_UP;
2700     case EL_TUBE_HORIZ_DOWN:    return GFX_TUBE_HORIZ_DOWN;
2701     case EL_TUBE_LEFT_UP:       return GFX_TUBE_LEFT_UP;
2702     case EL_TUBE_LEFT_DOWN:     return GFX_TUBE_LEFT_DOWN;
2703     case EL_TUBE_RIGHT_UP:      return GFX_TUBE_RIGHT_UP;
2704     case EL_TUBE_RIGHT_DOWN:    return GFX_TUBE_RIGHT_DOWN;
2705     case EL_SPRING:             return GFX_SPRING;
2706     case EL_SPRING_MOVING:      return GFX_SPRING;
2707     case EL_TRAP_INACTIVE:      return GFX_TRAP_INACTIVE;
2708     case EL_TRAP_ACTIVE:        return GFX_TRAP_ACTIVE;
2709     case EL_BD_WALL:            return GFX_BD_WALL;
2710     case EL_BD_ROCK:            return GFX_BD_ROCK;
2711     case EL_DX_SUPABOMB:        return GFX_DX_SUPABOMB;
2712     case EL_SP_MURPHY_CLONE:    return GFX_SP_MURPHY_CLONE;
2713
2714     default:
2715     {
2716       if (IS_CHAR(element))
2717         return GFX_CHAR_START + (element - EL_CHAR_START);
2718       else if (element >= EL_SP_START && element <= EL_SP_END)
2719       {
2720         int nr_element = element - EL_SP_START;
2721         int gfx_per_line = 8;
2722         int nr_graphic =
2723           (nr_element / gfx_per_line) * SP_PER_LINE +
2724           (nr_element % gfx_per_line);
2725
2726         return GFX_START_ROCKSSP + nr_graphic;
2727       }
2728       else
2729         return -1;
2730     }
2731   }
2732 }