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