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