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