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