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