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