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