rnd-20021019-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_EMPTY;
406
407   for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
408   {
409     for(x=0; x<lev_fieldx; x++)
410     {
411       if (!IS_MASSIVE(Feld[x][y]))
412         BorderElement = EL_STEELWALL;
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_EXPLOSION)
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_FIELD_FULL)
486           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
487         else
488           DrawLevelElement(next_jx, next_jy, EL_EMPTY);
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_EMPTY);
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_FIELD_EMPTY ||
609         Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
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_ROCK ||
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_EXPLOSION)
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 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 = 0;
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_LOOP)                 /* normal, looping animation */
721   {
722     frame = (sync_frame % (delay * num_frames)) / delay;
723   }
724   else if (mode & ANIM_LINEAR)          /* normal, non-looping animation */
725   {
726     frame = sync_frame / delay;
727
728     if (frame > num_frames - 1)
729       frame = num_frames - 1;
730   }
731   else if (mode & ANIM_PINGPONG)        /* use border frames once */
732   {
733     int max_anim_frames = 2 * num_frames - 2;
734
735     frame = (sync_frame % (delay * max_anim_frames)) / delay;
736     frame = (frame < num_frames ? frame : max_anim_frames - frame);
737   }
738   else if (mode & ANIM_PINGPONG2)       /* use border frames twice */
739   {
740     int max_anim_frames = 2 * num_frames;
741
742     frame = (sync_frame % (delay * max_anim_frames)) / delay;
743     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
744   }
745
746   if (mode & ANIM_REVERSE)              /* use reverse animation direction */
747     frame = num_frames - frame - 1;
748
749   return frame;
750 }
751
752 void DrawGraphicAnimationExt(int x, int y, int graphic,
753                              int frames, int delay, int mode, int mask_mode)
754 {
755   int phase = getGraphicAnimationPhase(frames, delay, mode);
756
757   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
758   {
759     if (mask_mode == USE_MASKING)
760       DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic + phase);
761     else
762       DrawGraphic(SCREENX(x), SCREENY(y), graphic + phase);
763   }
764 }
765
766 void DrawNewGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
767 {
768 #if 0
769   int delay = new_graphic_info[graphic].anim_delay;
770
771   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
772 #else
773   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
774 #endif
775   {
776     int frame = getNewGraphicAnimationFrame(graphic, -1);
777
778     if (mask_mode == USE_MASKING)
779       DrawNewGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
780     else
781       DrawNewGraphic(SCREENX(x), SCREENY(y), graphic, frame);
782   }
783 }
784
785 void DrawGraphicAnimation(int x, int y, int graphic,
786                           int frames, int delay, int mode)
787 {
788   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
789 }
790
791 void DrawNewGraphicAnimation(int x, int y, int graphic)
792 {
793   DrawNewGraphicAnimationExt(x, y, graphic, NO_MASKING);
794 }
795
796 void DrawGraphicAnimationThruMask(int x, int y, int graphic,
797                                   int frames, int delay, int mode)
798 {
799   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, USE_MASKING);
800 }
801
802 static void DrawGraphicAnimationShiftedThruMask(int sx, int sy,
803                                                 int sxx, int syy,
804                                                 int graphic,
805                                                 int frames, int delay,
806                                                 int mode)
807 {
808   int phase = getGraphicAnimationPhase(frames, delay, mode);
809
810   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic + phase, NO_CUTTING);
811 }
812
813 void getGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
814 {
815   if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
816   {
817     *bitmap = graphic_info[graphic].bitmap;
818     *x = graphic_info[graphic].src_x;
819     *y = graphic_info[graphic].src_y;
820   }
821   else if (graphic >= GFX_START_ROCKSELEMENTS &&
822            graphic <= GFX_END_ROCKSELEMENTS)
823   {
824     graphic -= GFX_START_ROCKSELEMENTS;
825     *bitmap = pix[PIX_ELEMENTS];
826     *x = (graphic % GFX_PER_LINE) * TILEX;
827     *y = (graphic / GFX_PER_LINE) * TILEY;
828   }
829   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
830   {
831     graphic -= GFX_START_ROCKSHEROES;
832     *bitmap = pix[PIX_HEROES];
833     *x = (graphic % HEROES_PER_LINE) * TILEX;
834     *y = (graphic / HEROES_PER_LINE) * TILEY;
835   }
836   else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
837   {
838     graphic -= GFX_START_ROCKSSP;
839     *bitmap = pix[PIX_SP];
840     *x = (graphic % SP_PER_LINE) * TILEX;
841     *y = (graphic / SP_PER_LINE) * TILEY;
842   }
843   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
844   {
845     graphic -= GFX_START_ROCKSDC;
846     *bitmap = pix[PIX_DC];
847     *x = (graphic % DC_PER_LINE) * TILEX;
848     *y = (graphic / DC_PER_LINE) * TILEY;
849   }
850   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
851   {
852     graphic -= GFX_START_ROCKSMORE;
853     *bitmap = pix[PIX_MORE];
854     *x = (graphic % MORE_PER_LINE) * TILEX;
855     *y = (graphic / MORE_PER_LINE) * TILEY;
856   }
857   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
858   {
859     graphic -= GFX_START_ROCKSFONT;
860     *bitmap = pix[PIX_FONT_EM];
861     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
862     *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
863   }
864   else
865   {
866     *bitmap = pix[PIX_SP];
867     *x = 0;
868     *y = 0;
869   }
870 }
871
872 void DrawGraphic(int x, int y, int graphic)
873 {
874 #if DEBUG
875   if (!IN_SCR_FIELD(x, y))
876   {
877     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
878     printf("DrawGraphic(): This should never happen!\n");
879     return;
880   }
881 #endif
882
883   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic);
884   MarkTileDirty(x, y);
885 }
886
887 void DrawNewGraphic(int x, int y, int graphic, int frame)
888 {
889 #if DEBUG
890   if (!IN_SCR_FIELD(x, y))
891   {
892     printf("DrawNewGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
893     printf("DrawNewGraphic(): This should never happen!\n");
894     return;
895   }
896 #endif
897
898   DrawNewGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
899                     graphic, frame);
900   MarkTileDirty(x, y);
901 }
902
903 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
904 {
905   Bitmap *src_bitmap;
906   int src_x, src_y;
907
908   getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
909   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
910 }
911
912 void DrawNewGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
913                        int frame)
914 {
915   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
916   int src_x = new_graphic_info[graphic].src_x;
917   int src_y = new_graphic_info[graphic].src_y;
918   int offset_x = new_graphic_info[graphic].offset_x;
919   int offset_y = new_graphic_info[graphic].offset_y;
920
921   src_x += frame * offset_x;
922   src_y += frame * offset_y;
923
924   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
925 }
926
927 void DrawGraphicThruMask(int x, int y, int graphic)
928 {
929 #if DEBUG
930   if (!IN_SCR_FIELD(x, y))
931   {
932     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
933     printf("DrawGraphicThruMask(): This should never happen!\n");
934     return;
935   }
936 #endif
937
938   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic);
939   MarkTileDirty(x, y);
940 }
941
942 void DrawNewGraphicThruMask(int x, int y, int graphic, int frame)
943 {
944 #if DEBUG
945   if (!IN_SCR_FIELD(x, y))
946   {
947     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
948     printf("DrawGraphicThruMask(): This should never happen!\n");
949     return;
950   }
951 #endif
952
953   DrawNewGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY,
954                             graphic, frame);
955   MarkTileDirty(x, y);
956 }
957
958 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic)
959 {
960   int tile = graphic;
961   int src_x, src_y;
962   Bitmap *src_bitmap;
963   GC drawing_gc;
964
965   if (graphic == GFX_LEERRAUM)
966     return;
967
968   getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
969   drawing_gc = src_bitmap->stored_clip_gc;
970
971   if (tile_clipmask[tile] != None)
972   {
973     SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
974     SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y);
975     BlitBitmapMasked(src_bitmap, d,
976                      src_x, src_y, TILEX, TILEY, dest_x, dest_y);
977   }
978   else
979   {
980 #if DEBUG
981 #ifndef TARGET_SDL
982     printf("DrawGraphicThruMask(): tile '%d' needs clipping!\n", tile);
983 #endif
984 #endif
985
986     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
987     BlitBitmapMasked(src_bitmap, d,
988                      src_x, src_y, TILEX, TILEY, dest_x, dest_y);
989   }
990 }
991
992 void DrawNewGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y,
993                                int graphic, int frame)
994 {
995   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
996   GC drawing_gc = src_bitmap->stored_clip_gc;
997   int src_x = new_graphic_info[graphic].src_x;
998   int src_y = new_graphic_info[graphic].src_y;
999   int offset_x = new_graphic_info[graphic].offset_x;
1000   int offset_y = new_graphic_info[graphic].offset_y;
1001
1002   src_x += frame * offset_x;
1003   src_y += frame * offset_y;
1004
1005   SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1006   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1007 }
1008
1009 void DrawMiniGraphic(int x, int y, int graphic)
1010 {
1011   DrawMiniGraphicExt(drawto,
1012                      SX + x * MINI_TILEX, SY + y * MINI_TILEY, graphic);
1013   MarkTileDirty(x / 2, y / 2);
1014 }
1015
1016 void DrawNewMiniGraphic(int x, int y, int graphic)
1017 {
1018   DrawNewMiniGraphicExt(drawto,
1019                         SX + x * MINI_TILEX, SY + y * MINI_TILEY, graphic);
1020   MarkTileDirty(x / 2, y / 2);
1021 }
1022
1023 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1024 {
1025   if (graphic >= GFX_START_ROCKSELEMENTS && graphic <= GFX_END_ROCKSELEMENTS)
1026   {
1027     graphic -= GFX_START_ROCKSELEMENTS;
1028     *bitmap = pix[PIX_ELEMENTS];
1029     *x = MINI_GFX_STARTX + (graphic % MINI_GFX_PER_LINE) * MINI_TILEX;
1030     *y = MINI_GFX_STARTY + (graphic / MINI_GFX_PER_LINE) * MINI_TILEY;
1031   }
1032   else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
1033   {
1034     graphic -= GFX_START_ROCKSSP;
1035     *bitmap = pix[PIX_SP];
1036     *x = MINI_SP_STARTX + (graphic % MINI_SP_PER_LINE) * MINI_TILEX;
1037     *y = MINI_SP_STARTY + (graphic / MINI_SP_PER_LINE) * MINI_TILEY;
1038   }
1039   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
1040   {
1041     graphic -= GFX_START_ROCKSDC;
1042     *bitmap = pix[PIX_DC];
1043     *x = MINI_DC_STARTX + (graphic % MINI_DC_PER_LINE) * MINI_TILEX;
1044     *y = MINI_DC_STARTY + (graphic / MINI_DC_PER_LINE) * MINI_TILEY;
1045   }
1046   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
1047   {
1048     graphic -= GFX_START_ROCKSMORE;
1049     *bitmap = pix[PIX_MORE];
1050     *x = MINI_MORE_STARTX + (graphic % MINI_MORE_PER_LINE) * MINI_TILEX;
1051     *y = MINI_MORE_STARTY + (graphic / MINI_MORE_PER_LINE) * MINI_TILEY;
1052   }
1053   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
1054   {
1055     graphic -= GFX_START_ROCKSFONT;
1056     *bitmap = pix[PIX_FONT_EM];
1057     *x = MINI_FONT_STARTX + (graphic % FONT_CHARS_PER_LINE) * FONT4_XSIZE;
1058     *y = MINI_FONT_STARTY + (graphic / FONT_CHARS_PER_LINE) * FONT4_YSIZE;
1059   }
1060   else
1061   {
1062     *bitmap = pix[PIX_SP];
1063     *x = MINI_SP_STARTX;
1064     *y = MINI_SP_STARTY;
1065   }
1066 }
1067
1068 void getNewMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1069 {
1070   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1071   int mini_startx = 0;
1072   int mini_starty = src_bitmap->height * 2 / 3;
1073   int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
1074   int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1075
1076   *bitmap = src_bitmap;
1077   *x = src_x;
1078   *y = src_y;
1079 }
1080
1081 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1082 {
1083   Bitmap *bitmap;
1084   int src_x, src_y;
1085
1086   getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
1087   BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1088 }
1089
1090 void DrawNewMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1091 {
1092 #if 1
1093   Bitmap *src_bitmap;
1094   int src_x, src_y;
1095
1096   getNewMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1097 #else
1098   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1099   int mini_startx = src_bitmap->width  * 2 / 3;
1100   int mini_starty = src_bitmap->height * 2 / 3;
1101   int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
1102   int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1103 #endif
1104
1105   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1106 }
1107
1108 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic,
1109                         int cut_mode, int mask_mode)
1110 {
1111   int width = TILEX, height = TILEY;
1112   int cx = 0, cy = 0;
1113   int src_x, src_y, dest_x, dest_y;
1114   int tile = graphic;
1115   Bitmap *src_bitmap;
1116   GC drawing_gc;
1117
1118   if (graphic < 0)
1119   {
1120     DrawGraphic(x, y, graphic);
1121     return;
1122   }
1123
1124   if (dx || dy)                 /* Verschiebung der Grafik? */
1125   {
1126     if (x < BX1)                /* Element kommt von links ins Bild */
1127     {
1128       x = BX1;
1129       width = dx;
1130       cx = TILEX - dx;
1131       dx = 0;
1132     }
1133     else if (x > BX2)           /* Element kommt von rechts ins Bild */
1134     {
1135       x = BX2;
1136       width = -dx;
1137       dx = TILEX + dx;
1138     }
1139     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
1140     {
1141       width += dx;
1142       cx = -dx;
1143       dx = 0;
1144     }
1145     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
1146       width -= dx;
1147     else if (dx)                /* allg. Bewegung in x-Richtung */
1148       MarkTileDirty(x + SIGN(dx), y);
1149
1150     if (y < BY1)                /* Element kommt von oben ins Bild */
1151     {
1152       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
1153         return;
1154
1155       y = BY1;
1156       height = dy;
1157       cy = TILEY - dy;
1158       dy = 0;
1159     }
1160     else if (y > BY2)           /* Element kommt von unten ins Bild */
1161     {
1162       y = BY2;
1163       height = -dy;
1164       dy = TILEY + dy;
1165     }
1166     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
1167     {
1168       height += dy;
1169       cy = -dy;
1170       dy = 0;
1171     }
1172     else if (dy > 0 && cut_mode == CUT_ABOVE)
1173     {
1174       if (y == BY2)             /* Element unterhalb des Bildes */
1175         return;
1176
1177       height = dy;
1178       cy = TILEY - dy;
1179       dy = TILEY;
1180       MarkTileDirty(x, y + 1);
1181     }                           /* Element verläßt unten das Bild */
1182     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1183       height -= dy;
1184     else if (dy)                /* allg. Bewegung in y-Richtung */
1185       MarkTileDirty(x, y + SIGN(dy));
1186   }
1187
1188   getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1189   drawing_gc = src_bitmap->stored_clip_gc;
1190
1191   src_x += cx;
1192   src_y += cy;
1193
1194   dest_x = FX + x * TILEX + dx;
1195   dest_y = FY + y * TILEY + dy;
1196
1197 #if DEBUG
1198   if (!IN_SCR_FIELD(x,y))
1199   {
1200     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1201     printf("DrawGraphicShifted(): This should never happen!\n");
1202     return;
1203   }
1204 #endif
1205
1206   if (mask_mode == USE_MASKING)
1207   {
1208     if (tile_clipmask[tile] != None)
1209     {
1210       SetClipMask(src_bitmap, tile_clip_gc, tile_clipmask[tile]);
1211       SetClipOrigin(src_bitmap, tile_clip_gc, dest_x, dest_y);
1212       BlitBitmapMasked(src_bitmap, drawto_field,
1213                        src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1214     }
1215     else
1216     {
1217 #if DEBUG
1218 #ifndef TARGET_SDL
1219       printf("DrawGraphicShifted(): tile '%d' needs clipping!\n", tile);
1220 #endif
1221 #endif
1222
1223       SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1224       BlitBitmapMasked(src_bitmap, drawto_field,
1225                        src_x, src_y, width, height, dest_x, dest_y);
1226     }
1227   }
1228   else
1229     BlitBitmap(src_bitmap, drawto_field,
1230                src_x, src_y, width, height, dest_x, dest_y);
1231
1232   MarkTileDirty(x,y);
1233 }
1234
1235 void DrawNewGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1236                         int cut_mode, int mask_mode)
1237 {
1238   Bitmap *src_bitmap;
1239   GC drawing_gc;
1240   int src_x;
1241   int src_y;
1242   int offset_x;
1243   int offset_y;
1244
1245   int width = TILEX, height = TILEY;
1246   int cx = 0, cy = 0;
1247   int dest_x, dest_y;
1248
1249   if (graphic < 0)
1250   {
1251     DrawNewGraphic(x, y, graphic, frame);
1252     return;
1253   }
1254
1255   if (dx || dy)                 /* Verschiebung der Grafik? */
1256   {
1257     if (x < BX1)                /* Element kommt von links ins Bild */
1258     {
1259       x = BX1;
1260       width = dx;
1261       cx = TILEX - dx;
1262       dx = 0;
1263     }
1264     else if (x > BX2)           /* Element kommt von rechts ins Bild */
1265     {
1266       x = BX2;
1267       width = -dx;
1268       dx = TILEX + dx;
1269     }
1270     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
1271     {
1272       width += dx;
1273       cx = -dx;
1274       dx = 0;
1275     }
1276     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
1277       width -= dx;
1278     else if (dx)                /* allg. Bewegung in x-Richtung */
1279       MarkTileDirty(x + SIGN(dx), y);
1280
1281     if (y < BY1)                /* Element kommt von oben ins Bild */
1282     {
1283       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
1284         return;
1285
1286       y = BY1;
1287       height = dy;
1288       cy = TILEY - dy;
1289       dy = 0;
1290     }
1291     else if (y > BY2)           /* Element kommt von unten ins Bild */
1292     {
1293       y = BY2;
1294       height = -dy;
1295       dy = TILEY + dy;
1296     }
1297     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
1298     {
1299       height += dy;
1300       cy = -dy;
1301       dy = 0;
1302     }
1303     else if (dy > 0 && cut_mode == CUT_ABOVE)
1304     {
1305       if (y == BY2)             /* Element unterhalb des Bildes */
1306         return;
1307
1308       height = dy;
1309       cy = TILEY - dy;
1310       dy = TILEY;
1311       MarkTileDirty(x, y + 1);
1312     }                           /* Element verläßt unten das Bild */
1313     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1314       height -= dy;
1315     else if (dy)                /* allg. Bewegung in y-Richtung */
1316       MarkTileDirty(x, y + SIGN(dy));
1317   }
1318
1319   src_bitmap = new_graphic_info[graphic].bitmap;
1320   drawing_gc = src_bitmap->stored_clip_gc;
1321   src_x = new_graphic_info[graphic].src_x;
1322   src_y = new_graphic_info[graphic].src_y;
1323   offset_x = new_graphic_info[graphic].offset_x;
1324   offset_y = new_graphic_info[graphic].offset_y;
1325
1326   src_x += frame * offset_x;
1327   src_y += frame * offset_y;
1328
1329   src_x += cx;
1330   src_y += cy;
1331
1332   dest_x = FX + x * TILEX + dx;
1333   dest_y = FY + y * TILEY + dy;
1334
1335 #if DEBUG
1336   if (!IN_SCR_FIELD(x,y))
1337   {
1338     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1339     printf("DrawGraphicShifted(): This should never happen!\n");
1340     return;
1341   }
1342 #endif
1343
1344   if (mask_mode == USE_MASKING)
1345     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1346
1347   BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1348              dest_x, dest_y);
1349
1350   MarkTileDirty(x,y);
1351 }
1352
1353 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1354                                 int cut_mode)
1355 {
1356   DrawGraphicShifted(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
1357 }
1358
1359 void DrawNewGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1360                                    int frame, int cut_mode)
1361 {
1362   DrawNewGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1363 }
1364
1365 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1366                           int cut_mode, int mask_mode)
1367 {
1368   int ux = LEVELX(x), uy = LEVELY(y);
1369   int graphic = el2gfx(element);
1370   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1371   int phase4 = phase8 / 2;
1372   int phase2  = phase8 / 4;
1373   int dir = MovDir[ux][uy];
1374
1375   if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1376   {
1377     graphic += 1 * !phase2;
1378
1379     if (dir == MV_UP)
1380       graphic += 1 * 2;
1381     else if (dir == MV_LEFT)
1382       graphic += 2 * 2;
1383     else if (dir == MV_DOWN)
1384       graphic += 3 * 2;
1385   }
1386   else if (element == EL_SP_SNIKSNAK)
1387   {
1388     if (dir == MV_LEFT)
1389       graphic = GFX_SP_SNIKSNAK_LEFT;
1390     else if (dir == MV_RIGHT)
1391       graphic = GFX_SP_SNIKSNAK_RIGHT;
1392     else if (dir == MV_UP)
1393       graphic = GFX_SP_SNIKSNAK_UP;
1394     else
1395       graphic = GFX_SP_SNIKSNAK_DOWN;
1396
1397     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1398   }
1399   else if (element == EL_SP_ELECTRON)
1400   {
1401     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1402   }
1403   else if (element == EL_MOLE || element == EL_PENGUIN ||
1404            element == EL_PIG || element == EL_DRAGON)
1405   {
1406     if (dir == MV_LEFT)
1407       graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1408                  element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1409                  element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1410     else if (dir == MV_RIGHT)
1411       graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1412                  element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1413                  element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1414     else if (dir == MV_UP)
1415       graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1416                  element == EL_PENGUIN ? GFX_PINGUIN_UP :
1417                  element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1418     else
1419       graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1420                  element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1421                  element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1422
1423     graphic += phase4;
1424   }
1425   else if (element == EL_SATELLITE)
1426   {
1427     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1428   }
1429   else if (element == EL_ACID)
1430   {
1431     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1432   }
1433   else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1434   {
1435     graphic += !phase2;
1436   }
1437   else if (element == EL_BALLOON)
1438   {
1439     graphic += phase4;
1440   }
1441   else if ((element == EL_ROCK ||
1442             element == EL_SP_ZONK ||
1443             element == EL_BD_ROCK ||
1444             element == EL_SP_INFOTRON ||
1445             IS_GEM(element))
1446            && !cut_mode)
1447   {
1448     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1449     {
1450       if (element == EL_ROCK ||
1451           element == EL_SP_ZONK ||
1452           element == EL_BD_ROCK)
1453       {
1454         if (dir == MV_LEFT)
1455           graphic += (4 - phase4) % 4;
1456         else if (dir == MV_RIGHT)
1457           graphic += phase4;
1458         else
1459           graphic += phase2 * 2;
1460       }
1461       else if (element != EL_SP_INFOTRON)
1462         graphic += phase2;
1463     }
1464   }
1465   else if (element == EL_MAGIC_WALL_ACTIVE ||
1466            element == EL_MAGIC_WALL_EMPTYING ||
1467            element == EL_BD_MAGIC_WALL_ACTIVE ||
1468            element == EL_BD_MAGIC_WALL_EMPTYING ||
1469            element == EL_MAGIC_WALL_FULL ||
1470            element == EL_BD_MAGIC_WALL_FULL)
1471   {
1472     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1473   }
1474   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1475   {
1476     graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1477     graphic += (x + 2 * y + 4) % 4;
1478   }
1479   else if (element == EL_WALL_GROWING)
1480   {
1481     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1482
1483     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1484       links_massiv = TRUE;
1485     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1486       rechts_massiv = TRUE;
1487
1488     if (links_massiv && rechts_massiv)
1489       graphic = GFX_MAUERWERK;
1490     else if (links_massiv)
1491       graphic = GFX_MAUER_R;
1492     else if (rechts_massiv)
1493       graphic = GFX_MAUER_L;
1494   }
1495 #if 0
1496   else if ((element == EL_INVISIBLE_STEELWALL ||
1497             element == EL_INVISIBLE_WALL ||
1498             element == EL_INVISIBLE_SAND) && game.light_time_left)
1499   {
1500     graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1501                element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1502                GFX_SAND_INVISIBLE_ON);
1503   }
1504 #endif
1505
1506   if (dx || dy)
1507     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1508   else if (mask_mode == USE_MASKING)
1509     DrawGraphicThruMask(x, y, graphic);
1510   else
1511     DrawGraphic(x, y, graphic);
1512 }
1513
1514 inline static int getFramePosition(int x, int y)
1515 {
1516   int element = Feld[x][y];
1517   int frame_pos = -1;
1518
1519   if (element == EL_QUICKSAND_FULL ||
1520       element == EL_MAGIC_WALL_FULL ||
1521       element == EL_BD_MAGIC_WALL_FULL)
1522     frame_pos = -1;
1523   else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1524     frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1525
1526   return frame_pos;
1527 }
1528
1529 inline static int getGfxAction(int x, int y)
1530 {
1531   int gfx_action = GFX_ACTION_DEFAULT;
1532
1533   if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1534     gfx_action = GfxAction[x][y];
1535   else if (IS_MOVING(x, y))
1536     gfx_action = GFX_ACTION_MOVING;
1537
1538   return gfx_action;
1539 }
1540
1541 void DrawNewScreenElementExt(int x, int y, int dx, int dy, int element,
1542                              int cut_mode, int mask_mode)
1543 {
1544   int ux = LEVELX(x), uy = LEVELY(y);
1545   int move_dir = MovDir[ux][uy];
1546   int move_pos = getFramePosition(ux, uy);
1547   int gfx_action = getGfxAction(ux, uy);
1548   int graphic = el_dir_act2img(element, move_dir, gfx_action);
1549   int frame = getNewGraphicAnimationFrame(graphic, move_pos);
1550
1551   if (element == EL_WALL_GROWING)
1552   {
1553     boolean left_stopped = FALSE, right_stopped = FALSE;
1554
1555     if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1556       left_stopped = TRUE;
1557     if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1558       right_stopped = TRUE;
1559
1560     if (left_stopped && right_stopped)
1561       graphic = IMG_WALL;
1562     else if (left_stopped)
1563     {
1564       graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1565       frame = new_graphic_info[graphic].anim_frames - 1;
1566     }
1567     else if (right_stopped)
1568     {
1569       graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1570       frame = new_graphic_info[graphic].anim_frames - 1;
1571     }
1572   }
1573 #if 0
1574   else if ((element == EL_ROCK ||
1575             element == EL_SP_ZONK ||
1576             element == EL_BD_ROCK ||
1577             element == EL_SP_INFOTRON ||
1578             IS_GEM(element))
1579            && !cut_mode)
1580   {
1581     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1582     {
1583       if (element == EL_ROCK ||
1584           element == EL_SP_ZONK ||
1585           element == EL_BD_ROCK)
1586       {
1587         if (move_dir == MV_LEFT)
1588           graphic += (4 - phase4) % 4;
1589         else if (move_dir == MV_RIGHT)
1590           graphic += phase4;
1591         else
1592           graphic += phase2 * 2;
1593       }
1594       else if (element != EL_SP_INFOTRON)
1595         graphic += phase2;
1596     }
1597   }
1598 #endif
1599   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1600   {
1601     graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1602                element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1603                element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1604                element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1605                IMG_AMOEBA_DEAD_PART1);
1606
1607     graphic += (x + 2 * y + 4) % 4;
1608   }
1609
1610   if (dx || dy)
1611     DrawNewGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1612   else if (mask_mode == USE_MASKING)
1613     DrawNewGraphicThruMask(x, y, graphic, frame);
1614   else
1615     DrawNewGraphic(x, y, graphic, frame);
1616 }
1617
1618 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1619                          int cut_mode, int mask_mode)
1620 {
1621   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1622     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1623                          cut_mode, mask_mode);
1624 }
1625
1626 void DrawNewLevelElementExt(int x, int y, int dx, int dy, int element,
1627                          int cut_mode, int mask_mode)
1628 {
1629   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1630     DrawNewScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1631                          cut_mode, mask_mode);
1632 }
1633
1634 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1635                               int cut_mode)
1636 {
1637   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1638 }
1639
1640 void DrawNewScreenElementShifted(int x, int y, int dx, int dy, int element,
1641                               int cut_mode)
1642 {
1643   DrawNewScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1644 }
1645
1646 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1647                              int cut_mode)
1648 {
1649   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1650 }
1651
1652 void DrawNewLevelElementShifted(int x, int y, int dx, int dy, int element,
1653                              int cut_mode)
1654 {
1655   DrawNewLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1656 }
1657
1658 void DrawScreenElementThruMask(int x, int y, int element)
1659 {
1660   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1661 }
1662
1663 void DrawNewScreenElementThruMask(int x, int y, int element)
1664 {
1665   DrawNewScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1666 }
1667
1668 void DrawLevelElementThruMask(int x, int y, int element)
1669 {
1670   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1671 }
1672
1673 void DrawNewLevelElementThruMask(int x, int y, int element)
1674 {
1675   DrawNewLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1676 }
1677
1678 void DrawLevelFieldThruMask(int x, int y)
1679 {
1680   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1681 }
1682
1683 void DrawNewLevelFieldThruMask(int x, int y)
1684 {
1685   DrawNewLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1686 }
1687
1688 void ErdreichAnbroeckeln(int x, int y)
1689 {
1690   Bitmap *src_bitmap;
1691   int src_x, src_y;
1692   int i, width, height, cx,cy;
1693   int ux = LEVELX(x), uy = LEVELY(y);
1694   int element, graphic;
1695   int snip = 4;
1696   static int xy[4][2] =
1697   {
1698     { 0, -1 },
1699     { -1, 0 },
1700     { +1, 0 },
1701     { 0, +1 }
1702   };
1703
1704   if (!IN_LEV_FIELD(ux, uy))
1705     return;
1706
1707   element = Feld[ux][uy];
1708
1709   if (element == EL_SAND ||
1710       element == EL_LANDMINE ||
1711       element == EL_TRAP ||
1712       element == EL_TRAP_ACTIVE)
1713   {
1714     if (!IN_SCR_FIELD(x, y))
1715       return;
1716
1717     graphic = GFX_ERDENRAND;
1718
1719     getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1720
1721     for(i=0; i<4; i++)
1722     {
1723       int uxx, uyy;
1724
1725       uxx = ux + xy[i][0];
1726       uyy = uy + xy[i][1];
1727       if (!IN_LEV_FIELD(uxx, uyy))
1728         element = EL_STEELWALL;
1729       else
1730         element = Feld[uxx][uyy];
1731
1732       if (element == EL_SAND ||
1733           element == EL_LANDMINE ||
1734           element == EL_TRAP ||
1735           element == EL_TRAP_ACTIVE)
1736         continue;
1737
1738       if (i == 1 || i == 2)
1739       {
1740         width = snip;
1741         height = TILEY;
1742         cx = (i == 2 ? TILEX - snip : 0);
1743         cy = 0;
1744       }
1745       else
1746       {
1747         width = TILEX;
1748         height = snip;
1749         cx = 0;
1750         cy = (i == 3 ? TILEY - snip : 0);
1751       }
1752
1753       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1754                  width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1755     }
1756
1757     MarkTileDirty(x, y);
1758   }
1759   else
1760   {
1761     graphic = GFX_ERDENRAND;
1762
1763     getGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1764
1765     for(i=0; i<4; i++)
1766     {
1767       int xx, yy, uxx, uyy;
1768
1769       xx = x + xy[i][0];
1770       yy = y + xy[i][1];
1771       uxx = ux + xy[i][0];
1772       uyy = uy + xy[i][1];
1773
1774       if (!IN_LEV_FIELD(uxx, uyy) ||
1775           (Feld[uxx][uyy] != EL_SAND &&
1776            Feld[uxx][uyy] != EL_LANDMINE &&
1777            Feld[uxx][uyy] != EL_TRAP &&
1778            Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1779           !IN_SCR_FIELD(xx, yy))
1780         continue;
1781
1782       if (i == 1 || i == 2)
1783       {
1784         width = snip;
1785         height = TILEY;
1786         cx = (i == 1 ? TILEX - snip : 0);
1787         cy = 0;
1788       }
1789       else
1790       {
1791         width = TILEX;
1792         height = snip;
1793         cx = 0;
1794         cy = (i==0 ? TILEY-snip : 0);
1795       }
1796
1797       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1798                  width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1799
1800       MarkTileDirty(xx, yy);
1801     }
1802   }
1803 }
1804
1805 void DrawScreenElement(int x, int y, int element)
1806 {
1807   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1808   ErdreichAnbroeckeln(x, y);
1809 }
1810
1811 void DrawNewScreenElement(int x, int y, int element)
1812 {
1813   DrawNewScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1814   ErdreichAnbroeckeln(x, y);
1815 }
1816
1817 void DrawLevelElement(int x, int y, int element)
1818 {
1819   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1820     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1821 }
1822
1823 void DrawNewLevelElement(int x, int y, int element)
1824 {
1825   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1826     DrawNewScreenElement(SCREENX(x), SCREENY(y), element);
1827 }
1828
1829 void DrawScreenField(int x, int y)
1830 {
1831   int ux = LEVELX(x), uy = LEVELY(y);
1832   int element, content;
1833
1834   if (!IN_LEV_FIELD(ux, uy))
1835   {
1836     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1837       element = EL_EMPTY;
1838     else
1839       element = BorderElement;
1840
1841     DrawScreenElement(x, y, element);
1842     return;
1843   }
1844
1845   element = Feld[ux][uy];
1846   content = Store[ux][uy];
1847
1848   if (IS_MOVING(ux, uy))
1849   {
1850     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1851     boolean cut_mode = NO_CUTTING;
1852
1853     if (element == EL_QUICKSAND_EMPTYING ||
1854         element == EL_MAGIC_WALL_EMPTYING ||
1855         element == EL_BD_MAGIC_WALL_EMPTYING ||
1856         element == EL_AMOEBA_DRIPPING)
1857       cut_mode = CUT_ABOVE;
1858     else if (element == EL_QUICKSAND_FILLING ||
1859              element == EL_MAGIC_WALL_FILLING ||
1860              element == EL_BD_MAGIC_WALL_FILLING)
1861       cut_mode = CUT_BELOW;
1862
1863     if (cut_mode == CUT_ABOVE)
1864       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1865     else
1866       DrawScreenElement(x, y, EL_EMPTY);
1867
1868     if (horiz_move)
1869       DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1870     else if (cut_mode == NO_CUTTING)
1871       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1872     else
1873       DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1874
1875     if (content == EL_ACID)
1876       DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1877   }
1878   else if (IS_BLOCKED(ux, uy))
1879   {
1880     int oldx, oldy;
1881     int sx, sy;
1882     int horiz_move;
1883     boolean cut_mode = NO_CUTTING;
1884     int element_old, content_old;
1885
1886     Blocked2Moving(ux, uy, &oldx, &oldy);
1887     sx = SCREENX(oldx);
1888     sy = SCREENY(oldy);
1889     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1890                   MovDir[oldx][oldy] == MV_RIGHT);
1891
1892     element_old = Feld[oldx][oldy];
1893     content_old = Store[oldx][oldy];
1894
1895     if (element_old == EL_QUICKSAND_EMPTYING ||
1896         element_old == EL_MAGIC_WALL_EMPTYING ||
1897         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1898         element_old == EL_AMOEBA_DRIPPING)
1899       cut_mode = CUT_ABOVE;
1900
1901     DrawScreenElement(x, y, EL_EMPTY);
1902
1903     if (horiz_move)
1904       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1905                                NO_CUTTING);
1906     else if (cut_mode == NO_CUTTING)
1907       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1908                                cut_mode);
1909     else
1910       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1911                                cut_mode);
1912   }
1913   else if (IS_DRAWABLE(element))
1914     DrawScreenElement(x, y, element);
1915   else
1916     DrawScreenElement(x, y, EL_EMPTY);
1917 }
1918
1919 void DrawNewScreenField(int x, int y)
1920 {
1921   int ux = LEVELX(x), uy = LEVELY(y);
1922   int element, content;
1923
1924   if (!IN_LEV_FIELD(ux, uy))
1925   {
1926     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1927       element = EL_EMPTY;
1928     else
1929       element = BorderElement;
1930
1931     DrawNewScreenElement(x, y, element);
1932     return;
1933   }
1934
1935   element = Feld[ux][uy];
1936   content = Store[ux][uy];
1937
1938   if (IS_MOVING(ux, uy))
1939   {
1940     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1941     boolean cut_mode = NO_CUTTING;
1942
1943     if (element == EL_QUICKSAND_EMPTYING ||
1944         element == EL_MAGIC_WALL_EMPTYING ||
1945         element == EL_BD_MAGIC_WALL_EMPTYING ||
1946         element == EL_AMOEBA_DRIPPING)
1947       cut_mode = CUT_ABOVE;
1948     else if (element == EL_QUICKSAND_FILLING ||
1949              element == EL_MAGIC_WALL_FILLING ||
1950              element == EL_BD_MAGIC_WALL_FILLING)
1951       cut_mode = CUT_BELOW;
1952
1953     if (cut_mode == CUT_ABOVE)
1954       DrawNewScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1955     else
1956       DrawNewScreenElement(x, y, EL_EMPTY);
1957
1958     if (horiz_move)
1959       DrawNewScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1960     else if (cut_mode == NO_CUTTING)
1961       DrawNewScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1962     else
1963       DrawNewScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1964
1965     if (content == EL_ACID)
1966       DrawNewLevelElementThruMask(ux, uy + 1, EL_ACID);
1967   }
1968   else if (IS_BLOCKED(ux, uy))
1969   {
1970     int oldx, oldy;
1971     int sx, sy;
1972     int horiz_move;
1973     boolean cut_mode = NO_CUTTING;
1974     int element_old, content_old;
1975
1976     Blocked2Moving(ux, uy, &oldx, &oldy);
1977     sx = SCREENX(oldx);
1978     sy = SCREENY(oldy);
1979     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1980                   MovDir[oldx][oldy] == MV_RIGHT);
1981
1982     element_old = Feld[oldx][oldy];
1983     content_old = Store[oldx][oldy];
1984
1985     if (element_old == EL_QUICKSAND_EMPTYING ||
1986         element_old == EL_MAGIC_WALL_EMPTYING ||
1987         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1988         element_old == EL_AMOEBA_DRIPPING)
1989       cut_mode = CUT_ABOVE;
1990
1991     DrawNewScreenElement(x, y, EL_EMPTY);
1992
1993     if (horiz_move)
1994       DrawNewScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1995                                NO_CUTTING);
1996     else if (cut_mode == NO_CUTTING)
1997       DrawNewScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1998                                cut_mode);
1999     else
2000       DrawNewScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2001                                cut_mode);
2002   }
2003   else if (IS_DRAWABLE(element))
2004     DrawNewScreenElement(x, y, element);
2005   else
2006     DrawNewScreenElement(x, y, EL_EMPTY);
2007 }
2008
2009 void DrawLevelField(int x, int y)
2010 {
2011   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2012     DrawScreenField(SCREENX(x), SCREENY(y));
2013   else if (IS_MOVING(x, y))
2014   {
2015     int newx,newy;
2016
2017     Moving2Blocked(x, y, &newx, &newy);
2018     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2019       DrawScreenField(SCREENX(newx), SCREENY(newy));
2020   }
2021   else if (IS_BLOCKED(x, y))
2022   {
2023     int oldx, oldy;
2024
2025     Blocked2Moving(x, y, &oldx, &oldy);
2026     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2027       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2028   }
2029 }
2030
2031 void DrawNewLevelField(int x, int y)
2032 {
2033   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2034     DrawNewScreenField(SCREENX(x), SCREENY(y));
2035   else if (IS_MOVING(x, y))
2036   {
2037     int newx,newy;
2038
2039     Moving2Blocked(x, y, &newx, &newy);
2040     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2041       DrawNewScreenField(SCREENX(newx), SCREENY(newy));
2042   }
2043   else if (IS_BLOCKED(x, y))
2044   {
2045     int oldx, oldy;
2046
2047     Blocked2Moving(x, y, &oldx, &oldy);
2048     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2049       DrawNewScreenField(SCREENX(oldx), SCREENY(oldy));
2050   }
2051 }
2052
2053 void DrawMiniElement(int x, int y, int element)
2054 {
2055   int graphic;
2056
2057   if (!element)
2058   {
2059     DrawMiniGraphic(x, y, -1);
2060     return;
2061   }
2062
2063   graphic = el2gfx(element);
2064   DrawMiniGraphic(x, y, graphic);
2065 }
2066
2067 void DrawNewMiniElement(int x, int y, int element)
2068 {
2069   int graphic;
2070
2071 #if 0
2072   if (!element)
2073   {
2074     DrawNewMiniGraphic(x, y, -1);
2075     return;
2076   }
2077 #endif
2078
2079   graphic = el2img(element);
2080   DrawNewMiniGraphic(x, y, graphic);
2081 }
2082
2083 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2084 {
2085   int x = sx + scroll_x, y = sy + scroll_y;
2086
2087   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2088     DrawMiniElement(sx, sy, EL_EMPTY);
2089   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2090     DrawMiniElement(sx, sy, Feld[x][y]);
2091   else
2092   {
2093     int steel_type, steel_position;
2094     int border[6][2] =
2095     {
2096       { GFX_VSTEEL_UPPER_LEFT,  GFX_ISTEEL_UPPER_LEFT  },
2097       { GFX_VSTEEL_UPPER_RIGHT, GFX_ISTEEL_UPPER_RIGHT },
2098       { GFX_VSTEEL_LOWER_LEFT,  GFX_ISTEEL_LOWER_LEFT  },
2099       { GFX_VSTEEL_LOWER_RIGHT, GFX_ISTEEL_LOWER_RIGHT },
2100       { GFX_VSTEEL_VERTICAL,    GFX_ISTEEL_VERTICAL    },
2101       { GFX_VSTEEL_HORIZONTAL,  GFX_ISTEEL_HORIZONTAL  }
2102     };
2103
2104     steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2105     steel_position = (x == -1 && y == -1                        ? 0 :
2106                       x == lev_fieldx && y == -1                ? 1 :
2107                       x == -1 && y == lev_fieldy                ? 2 :
2108                       x == lev_fieldx && y == lev_fieldy        ? 3 :
2109                       x == -1 || x == lev_fieldx                ? 4 :
2110                       y == -1 || y == lev_fieldy                ? 5 : -1);
2111
2112     if (steel_position != -1)
2113       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
2114   }
2115 }
2116
2117 void DrawNewMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2118 {
2119   int x = sx + scroll_x, y = sy + scroll_y;
2120
2121   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2122     DrawNewMiniElement(sx, sy, EL_EMPTY);
2123   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2124     DrawNewMiniElement(sx, sy, Feld[x][y]);
2125   else
2126   {
2127     int steel_type, steel_position;
2128     int border[6][2] =
2129     {
2130       { IMG_STEELWALL_TOPLEFT,          IMG_INVISIBLE_STEELWALL_TOPLEFT     },
2131       { IMG_STEELWALL_TOPRIGHT,         IMG_INVISIBLE_STEELWALL_TOPRIGHT    },
2132       { IMG_STEELWALL_BOTTOMLEFT,       IMG_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2133       { IMG_STEELWALL_BOTTOMRIGHT,      IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2134       { IMG_STEELWALL_VERTICAL,         IMG_INVISIBLE_STEELWALL_VERTICAL    },
2135       { IMG_STEELWALL_HORIZONTAL,       IMG_INVISIBLE_STEELWALL_HORIZONTAL  }
2136     };
2137
2138     steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2139     steel_position = (x == -1 && y == -1                        ? 0 :
2140                       x == lev_fieldx && y == -1                ? 1 :
2141                       x == -1 && y == lev_fieldy                ? 2 :
2142                       x == lev_fieldx && y == lev_fieldy        ? 3 :
2143                       x == -1 || x == lev_fieldx                ? 4 :
2144                       y == -1 || y == lev_fieldy                ? 5 : -1);
2145
2146     if (steel_position != -1)
2147       DrawNewMiniGraphic(sx, sy, border[steel_position][steel_type]);
2148   }
2149 }
2150
2151 void DrawMicroElement(int xpos, int ypos, int element)
2152 {
2153   int graphic;
2154
2155   if (element == EL_EMPTY)
2156     return;
2157
2158   graphic = el2gfx(element);
2159
2160   if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
2161   {
2162     graphic -= GFX_START_ROCKSSP;
2163     BlitBitmap(pix[PIX_SP], drawto,
2164                MICRO_SP_STARTX + (graphic % MICRO_SP_PER_LINE) * MICRO_TILEX,
2165                MICRO_SP_STARTY + (graphic / MICRO_SP_PER_LINE) * MICRO_TILEY,
2166                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
2167   }
2168   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
2169   {
2170     graphic -= GFX_START_ROCKSDC;
2171     BlitBitmap(pix[PIX_DC], drawto,
2172                MICRO_DC_STARTX + (graphic % MICRO_DC_PER_LINE) * MICRO_TILEX,
2173                MICRO_DC_STARTY + (graphic / MICRO_DC_PER_LINE) * MICRO_TILEY,
2174                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
2175   }
2176   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
2177   {
2178     graphic -= GFX_START_ROCKSMORE;
2179     BlitBitmap(pix[PIX_MORE], drawto,
2180                MICRO_MORE_STARTX + (graphic % MICRO_MORE_PER_LINE)*MICRO_TILEX,
2181                MICRO_MORE_STARTY + (graphic / MICRO_MORE_PER_LINE)*MICRO_TILEY,
2182                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
2183   }
2184   else if (graphic >= GFX_CHAR_START && graphic <= GFX_CHAR_END)
2185   {
2186     graphic -= GFX_CHAR_START;
2187     BlitBitmap(pix[PIX_FONT_EM], drawto,
2188                MICRO_FONT_STARTX + (graphic % MICRO_GFX_PER_LINE)* MICRO_TILEX,
2189                MICRO_FONT_STARTY + (graphic / MICRO_GFX_PER_LINE)* MICRO_TILEY,
2190                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
2191   }
2192   else
2193     BlitBitmap(pix[PIX_ELEMENTS], drawto,
2194                MICRO_GFX_STARTX + (graphic % MICRO_GFX_PER_LINE) * MICRO_TILEX,
2195                MICRO_GFX_STARTY + (graphic / MICRO_GFX_PER_LINE) * MICRO_TILEY,
2196                MICRO_TILEX, MICRO_TILEY, xpos, ypos);
2197 }
2198
2199 void DrawLevel()
2200 {
2201   int x,y;
2202
2203   ClearWindow();
2204
2205   for(x=BX1; x<=BX2; x++)
2206     for(y=BY1; y<=BY2; y++)
2207       DrawNewScreenField(x, y);
2208
2209   redraw_mask |= REDRAW_FIELD;
2210 }
2211
2212 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2213 {
2214   int x,y;
2215
2216   for(x=0; x<size_x; x++)
2217     for(y=0; y<size_y; y++)
2218       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2219
2220   redraw_mask |= REDRAW_FIELD;
2221 }
2222
2223 void DrawNewMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2224 {
2225   int x,y;
2226
2227   for(x=0; x<size_x; x++)
2228     for(y=0; y<size_y; y++)
2229       DrawNewMiniElementOrWall(x, y, scroll_x, scroll_y);
2230
2231   redraw_mask |= REDRAW_FIELD;
2232 }
2233
2234 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
2235 {
2236   int x, y;
2237
2238   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
2239
2240   if (lev_fieldx < STD_LEV_FIELDX)
2241     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
2242   if (lev_fieldy < STD_LEV_FIELDY)
2243     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
2244
2245   xpos += MICRO_TILEX;
2246   ypos += MICRO_TILEY;
2247
2248   for(x=-1; x<=STD_LEV_FIELDX; x++)
2249   {
2250     for(y=-1; y<=STD_LEV_FIELDY; y++)
2251     {
2252       int lx = from_x + x, ly = from_y + y;
2253
2254       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
2255         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2256                          Ur[lx][ly]);
2257       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
2258         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2259                          BorderElement);
2260     }
2261   }
2262
2263   redraw_mask |= REDRAW_MICROLEVEL;
2264 }
2265
2266 #define MICROLABEL_EMPTY                0
2267 #define MICROLABEL_LEVEL_NAME           1
2268 #define MICROLABEL_CREATED_BY           2
2269 #define MICROLABEL_LEVEL_AUTHOR         3
2270 #define MICROLABEL_IMPORTED_FROM        4
2271 #define MICROLABEL_LEVEL_IMPORT_INFO    5
2272
2273 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
2274
2275 static void DrawMicroLevelLabelExt(int mode)
2276 {
2277   char label_text[MAX_MICROLABEL_SIZE + 1];
2278
2279   ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
2280
2281   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
2282                        mode == MICROLABEL_CREATED_BY ? "created by" :
2283                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2284                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
2285                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
2286                        leveldir_current->imported_from : ""),
2287           MAX_MICROLABEL_SIZE);
2288   label_text[MAX_MICROLABEL_SIZE] = '\0';
2289
2290   if (strlen(label_text) > 0)
2291   {
2292     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
2293     int lypos = MICROLABEL_YPOS;
2294
2295     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
2296   }
2297
2298   redraw_mask |= REDRAW_MICROLEVEL;
2299 }
2300
2301 void DrawMicroLevel(int xpos, int ypos, boolean restart)
2302 {
2303   static unsigned long scroll_delay = 0;
2304   static unsigned long label_delay = 0;
2305   static int from_x, from_y, scroll_direction;
2306   static int label_state, label_counter;
2307
2308   if (restart)
2309   {
2310     from_x = from_y = 0;
2311     scroll_direction = MV_RIGHT;
2312     label_state = 1;
2313     label_counter = 0;
2314
2315     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2316     DrawMicroLevelLabelExt(label_state);
2317
2318     /* initialize delay counters */
2319     DelayReached(&scroll_delay, 0);
2320     DelayReached(&label_delay, 0);
2321
2322     return;
2323   }
2324
2325   /* scroll micro level, if needed */
2326   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
2327       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
2328   {
2329     switch (scroll_direction)
2330     {
2331       case MV_LEFT:
2332         if (from_x > 0)
2333           from_x--;
2334         else
2335           scroll_direction = MV_UP;
2336         break;
2337
2338       case MV_RIGHT:
2339         if (from_x < lev_fieldx - STD_LEV_FIELDX)
2340           from_x++;
2341         else
2342           scroll_direction = MV_DOWN;
2343         break;
2344
2345       case MV_UP:
2346         if (from_y > 0)
2347           from_y--;
2348         else
2349           scroll_direction = MV_RIGHT;
2350         break;
2351
2352       case MV_DOWN:
2353         if (from_y < lev_fieldy - STD_LEV_FIELDY)
2354           from_y++;
2355         else
2356           scroll_direction = MV_LEFT;
2357         break;
2358
2359       default:
2360         break;
2361     }
2362
2363     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2364   }
2365
2366   /* redraw micro level label, if needed */
2367   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2368       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2369       strcmp(level.author, leveldir_current->name) != 0 &&
2370       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2371   {
2372     int max_label_counter = 23;
2373
2374     if (leveldir_current->imported_from != NULL)
2375       max_label_counter += 14;
2376
2377     label_counter = (label_counter + 1) % max_label_counter;
2378     label_state = (label_counter >= 0 && label_counter <= 7 ?
2379                    MICROLABEL_LEVEL_NAME :
2380                    label_counter >= 9 && label_counter <= 12 ?
2381                    MICROLABEL_CREATED_BY :
2382                    label_counter >= 14 && label_counter <= 21 ?
2383                    MICROLABEL_LEVEL_AUTHOR :
2384                    label_counter >= 23 && label_counter <= 26 ?
2385                    MICROLABEL_IMPORTED_FROM :
2386                    label_counter >= 28 && label_counter <= 35 ?
2387                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2388     DrawMicroLevelLabelExt(label_state);
2389   }
2390 }
2391
2392 int REQ_in_range(int x, int y)
2393 {
2394   if (y > DY+249 && y < DY+278)
2395   {
2396     if (x > DX+1 && x < DX+48)
2397       return 1;
2398     else if (x > DX+51 && x < DX+98) 
2399       return 2;
2400   }
2401   return 0;
2402 }
2403
2404 #define MAX_REQUEST_LINES               13
2405 #define MAX_REQUEST_LINE_LEN            7
2406
2407 boolean Request(char *text, unsigned int req_state)
2408 {
2409   int mx, my, ty, result = -1;
2410   unsigned int old_door_state;
2411
2412 #if defined(PLATFORM_UNIX)
2413   /* pause network game while waiting for request to answer */
2414   if (options.network &&
2415       game_status == PLAYING &&
2416       req_state & REQUEST_WAIT_FOR)
2417     SendToServer_PausePlaying();
2418 #endif
2419
2420   old_door_state = GetDoorState();
2421
2422   UnmapAllGadgets();
2423
2424   CloseDoor(DOOR_CLOSE_1);
2425
2426   /* save old door content */
2427   BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2428              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2429              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2430
2431   /* clear door drawing field */
2432   ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
2433
2434   /* write text for request */
2435   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2436   {
2437     char text_line[MAX_REQUEST_LINE_LEN + 1];
2438     int tx, tl, tc;
2439
2440     if (!*text)
2441       break;
2442
2443     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2444     {
2445       tc = *(text + tx);
2446       if (!tc || tc == ' ')
2447         break;
2448     }
2449
2450     if (!tl)
2451     { 
2452       text++; 
2453       ty--; 
2454       continue; 
2455     }
2456
2457     strncpy(text_line, text, tl);
2458     text_line[tl] = 0;
2459
2460     DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
2461                 text_line, FS_SMALL, FC_YELLOW);
2462
2463     text += tl + (tc == ' ' ? 1 : 0);
2464   }
2465
2466   if (req_state & REQ_ASK)
2467   {
2468     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2469     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2470   }
2471   else if (req_state & REQ_CONFIRM)
2472   {
2473     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2474   }
2475   else if (req_state & REQ_PLAYER)
2476   {
2477     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2478     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2479     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2480     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2481   }
2482
2483   /* copy request gadgets to door backbuffer */
2484   BlitBitmap(drawto, pix[PIX_DB_DOOR],
2485              DX, DY, DXSIZE, DYSIZE,
2486              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2487
2488   OpenDoor(DOOR_OPEN_1);
2489
2490 #if 0
2491   ClearEventQueue();
2492 #endif
2493
2494   if (!(req_state & REQUEST_WAIT_FOR))
2495     return(FALSE);
2496
2497   if (game_status != MAINMENU)
2498     InitAnimation();
2499
2500   button_status = MB_RELEASED;
2501
2502   request_gadget_id = -1;
2503
2504   while(result < 0)
2505   {
2506     if (PendingEvent())
2507     {
2508       Event event;
2509
2510       NextEvent(&event);
2511
2512       switch(event.type)
2513       {
2514         case EVENT_BUTTONPRESS:
2515         case EVENT_BUTTONRELEASE:
2516         case EVENT_MOTIONNOTIFY:
2517         {
2518           if (event.type == EVENT_MOTIONNOTIFY)
2519           {
2520             if (!PointerInWindow(window))
2521               continue; /* window and pointer are on different screens */
2522
2523             if (!button_status)
2524               continue;
2525
2526             motion_status = TRUE;
2527             mx = ((MotionEvent *) &event)->x;
2528             my = ((MotionEvent *) &event)->y;
2529           }
2530           else
2531           {
2532             motion_status = FALSE;
2533             mx = ((ButtonEvent *) &event)->x;
2534             my = ((ButtonEvent *) &event)->y;
2535             if (event.type == EVENT_BUTTONPRESS)
2536               button_status = ((ButtonEvent *) &event)->button;
2537             else
2538               button_status = MB_RELEASED;
2539           }
2540
2541           /* this sets 'request_gadget_id' */
2542           HandleGadgets(mx, my, button_status);
2543
2544           switch(request_gadget_id)
2545           {
2546             case TOOL_CTRL_ID_YES:
2547               result = TRUE;
2548               break;
2549             case TOOL_CTRL_ID_NO:
2550               result = FALSE;
2551               break;
2552             case TOOL_CTRL_ID_CONFIRM:
2553               result = TRUE | FALSE;
2554               break;
2555
2556             case TOOL_CTRL_ID_PLAYER_1:
2557               result = 1;
2558               break;
2559             case TOOL_CTRL_ID_PLAYER_2:
2560               result = 2;
2561               break;
2562             case TOOL_CTRL_ID_PLAYER_3:
2563               result = 3;
2564               break;
2565             case TOOL_CTRL_ID_PLAYER_4:
2566               result = 4;
2567               break;
2568
2569             default:
2570               break;
2571           }
2572
2573           break;
2574         }
2575
2576         case EVENT_KEYPRESS:
2577           switch(GetEventKey((KeyEvent *)&event, TRUE))
2578           {
2579             case KSYM_Return:
2580               result = 1;
2581               break;
2582
2583             case KSYM_Escape:
2584               result = 0;
2585               break;
2586
2587             default:
2588               break;
2589           }
2590           if (req_state & REQ_PLAYER)
2591             result = 0;
2592           break;
2593
2594         case EVENT_KEYRELEASE:
2595           ClearPlayerAction();
2596           break;
2597
2598         default:
2599           HandleOtherEvents(&event);
2600           break;
2601       }
2602     }
2603     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2604     {
2605       int joy = AnyJoystick();
2606
2607       if (joy & JOY_BUTTON_1)
2608         result = 1;
2609       else if (joy & JOY_BUTTON_2)
2610         result = 0;
2611     }
2612
2613     DoAnimation();
2614
2615     /* don't eat all CPU time */
2616     Delay(10);
2617   }
2618
2619   if (game_status != MAINMENU)
2620     StopAnimation();
2621
2622   UnmapToolButtons();
2623
2624   if (!(req_state & REQ_STAY_OPEN))
2625   {
2626     CloseDoor(DOOR_CLOSE_1);
2627
2628     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2629     {
2630       BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2631                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2632                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2633       OpenDoor(DOOR_OPEN_1);
2634     }
2635   }
2636
2637   RemapAllGadgets();
2638
2639 #if defined(PLATFORM_UNIX)
2640   /* continue network game after request */
2641   if (options.network &&
2642       game_status == PLAYING &&
2643       req_state & REQUEST_WAIT_FOR)
2644     SendToServer_ContinuePlaying();
2645 #endif
2646
2647   return(result);
2648 }
2649
2650 unsigned int OpenDoor(unsigned int door_state)
2651 {
2652   unsigned int new_door_state;
2653
2654   if (door_state & DOOR_COPY_BACK)
2655   {
2656     BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2657                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2658                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2659     door_state &= ~DOOR_COPY_BACK;
2660   }
2661
2662   new_door_state = MoveDoor(door_state);
2663
2664   return(new_door_state);
2665 }
2666
2667 unsigned int CloseDoor(unsigned int door_state)
2668 {
2669   unsigned int new_door_state;
2670
2671   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2672              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2673   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2674              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2675
2676   new_door_state = MoveDoor(door_state);
2677
2678   return(new_door_state);
2679 }
2680
2681 unsigned int GetDoorState()
2682 {
2683   return MoveDoor(DOOR_GET_STATE);
2684 }
2685
2686 unsigned int SetDoorState(unsigned int door_state)
2687 {
2688   return MoveDoor(door_state | DOOR_SET_STATE);
2689 }
2690
2691 unsigned int MoveDoor(unsigned int door_state)
2692 {
2693   static int door1 = DOOR_OPEN_1;
2694   static int door2 = DOOR_CLOSE_2;
2695   static unsigned long door_delay = 0;
2696   int x, start, stepsize = 2;
2697   unsigned long door_delay_value = stepsize * 5;
2698
2699   if (door_state == DOOR_GET_STATE)
2700     return(door1 | door2);
2701
2702   if (door_state & DOOR_SET_STATE)
2703   {
2704     if (door_state & DOOR_ACTION_1)
2705       door1 = door_state & DOOR_ACTION_1;
2706     if (door_state & DOOR_ACTION_2)
2707       door2 = door_state & DOOR_ACTION_2;
2708
2709     return(door1 | door2);
2710   }
2711
2712   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2713     door_state &= ~DOOR_OPEN_1;
2714   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2715     door_state &= ~DOOR_CLOSE_1;
2716   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2717     door_state &= ~DOOR_OPEN_2;
2718   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2719     door_state &= ~DOOR_CLOSE_2;
2720
2721   if (setup.quick_doors)
2722   {
2723     stepsize = 20;
2724     door_delay_value = 0;
2725     StopSound(SND_MENU_DOOR_OPENING);
2726     StopSound(SND_MENU_DOOR_CLOSING);
2727   }
2728
2729   if (door_state & DOOR_ACTION)
2730   {
2731     if (!(door_state & DOOR_NO_DELAY))
2732     {
2733       /* opening door sound has priority over simultaneously closing door */
2734       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2735         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2736       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2737         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2738     }
2739
2740     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2741
2742     for(x=start; x<=DXSIZE; x+=stepsize)
2743     {
2744       Bitmap *bitmap = pix[PIX_DOOR];
2745       GC gc = bitmap->stored_clip_gc;
2746
2747       WaitUntilDelayReached(&door_delay, door_delay_value);
2748
2749       if (door_state & DOOR_ACTION_1)
2750       {
2751         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2752         int j = (DXSIZE - i) / 3;
2753
2754         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2755                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2756                    DXSIZE,DYSIZE - i/2, DX, DY);
2757
2758         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2759
2760         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2761         BlitBitmapMasked(bitmap, drawto,
2762                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2763                          DX + DXSIZE - i, DY + j);
2764         BlitBitmapMasked(bitmap, drawto,
2765                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2766                          DX + DXSIZE - i, DY + 140 + j);
2767         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2768         BlitBitmapMasked(bitmap, drawto,
2769                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2770                          DX, DY);
2771         BlitBitmapMasked(bitmap, drawto,
2772                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2773                          DX, DY + 140 - j);
2774
2775         BlitBitmapMasked(bitmap, drawto,
2776                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2777                          DX, DY + 77 - j);
2778         BlitBitmapMasked(bitmap, drawto,
2779                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2780                          DX, DY + 203 - j);
2781         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2782         BlitBitmapMasked(bitmap, drawto,
2783                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2784                          DX + DXSIZE - i, DY + 77 + j);
2785         BlitBitmapMasked(bitmap, drawto,
2786                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2787                          DX + DXSIZE - i, DY + 203 + j);
2788
2789         redraw_mask |= REDRAW_DOOR_1;
2790       }
2791
2792       if (door_state & DOOR_ACTION_2)
2793       {
2794         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2795         int j = (VXSIZE - i) / 3;
2796
2797         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2798                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2799                    VXSIZE, VYSIZE - i/2, VX, VY);
2800
2801         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2802
2803         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2804         BlitBitmapMasked(bitmap, drawto,
2805                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2806                          VX + VXSIZE-i, VY+j);
2807         SetClipOrigin(bitmap, gc,
2808                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2809         BlitBitmapMasked(bitmap, drawto,
2810                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2811                          VX, VY);
2812
2813         BlitBitmapMasked(bitmap, drawto,
2814                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2815                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2816         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2817         BlitBitmapMasked(bitmap, drawto,
2818                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2819                          i, VYSIZE / 2 - j,
2820                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2821
2822         redraw_mask |= REDRAW_DOOR_2;
2823       }
2824
2825       BackToFront();
2826
2827       if (game_status == MAINMENU)
2828         DoAnimation();
2829     }
2830   }
2831
2832   if (setup.quick_doors)
2833   {
2834     StopSound(SND_MENU_DOOR_OPENING);
2835     StopSound(SND_MENU_DOOR_CLOSING);
2836   }
2837
2838   if (door_state & DOOR_ACTION_1)
2839     door1 = door_state & DOOR_ACTION_1;
2840   if (door_state & DOOR_ACTION_2)
2841     door2 = door_state & DOOR_ACTION_2;
2842
2843   return (door1 | door2);
2844 }
2845
2846 void DrawSpecialEditorDoor()
2847 {
2848   /* draw bigger toolbox window */
2849   BlitBitmap(pix[PIX_DOOR], drawto,
2850              DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2851
2852   redraw_mask |= REDRAW_ALL;
2853 }
2854
2855 void UndrawSpecialEditorDoor()
2856 {
2857   /* draw normal tape recorder window */
2858   BlitBitmap(pix[PIX_BACK], drawto,
2859              562, 344, 108, 56, EX - 4, EY - 12);
2860
2861   redraw_mask |= REDRAW_ALL;
2862 }
2863
2864 #ifndef TARGET_SDL
2865 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2866 {
2867   XImage *pixel_image;
2868   unsigned long pixel_value;
2869
2870   pixel_image = XGetImage(display, bitmap->drawable,
2871                           x, y, 1, 1, AllPlanes, ZPixmap);
2872   pixel_value = XGetPixel(pixel_image, 0, 0);
2873
2874   XDestroyImage(pixel_image);
2875
2876   return pixel_value;
2877 }
2878 #endif
2879
2880 /* ---------- new tool button stuff ---------------------------------------- */
2881
2882 /* graphic position values for tool buttons */
2883 #define TOOL_BUTTON_YES_XPOS            2
2884 #define TOOL_BUTTON_YES_YPOS            250
2885 #define TOOL_BUTTON_YES_GFX_YPOS        0
2886 #define TOOL_BUTTON_YES_XSIZE           46
2887 #define TOOL_BUTTON_YES_YSIZE           28
2888 #define TOOL_BUTTON_NO_XPOS             52
2889 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2890 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2891 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2892 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2893 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2894 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2895 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2896 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2897 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2898 #define TOOL_BUTTON_PLAYER_XSIZE        30
2899 #define TOOL_BUTTON_PLAYER_YSIZE        30
2900 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2901 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2902 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2903 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2904 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2905                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2906 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2907                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2908 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2909                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2910 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2911                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2912 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2913                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2914 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2915                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2916 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2917                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2918 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2919                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2920
2921 static struct
2922 {
2923   int xpos, ypos;
2924   int x, y;
2925   int width, height;
2926   int gadget_id;
2927   char *infotext;
2928 } toolbutton_info[NUM_TOOL_BUTTONS] =
2929 {
2930   {
2931     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2932     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2933     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2934     TOOL_CTRL_ID_YES,
2935     "yes"
2936   },
2937   {
2938     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2939     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2940     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2941     TOOL_CTRL_ID_NO,
2942     "no"
2943   },
2944   {
2945     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2946     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2947     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2948     TOOL_CTRL_ID_CONFIRM,
2949     "confirm"
2950   },
2951   {
2952     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2953     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2954     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2955     TOOL_CTRL_ID_PLAYER_1,
2956     "player 1"
2957   },
2958   {
2959     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2960     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2961     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2962     TOOL_CTRL_ID_PLAYER_2,
2963     "player 2"
2964   },
2965   {
2966     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2967     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2968     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2969     TOOL_CTRL_ID_PLAYER_3,
2970     "player 3"
2971   },
2972   {
2973     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2974     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2975     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2976     TOOL_CTRL_ID_PLAYER_4,
2977     "player 4"
2978   }
2979 };
2980
2981 void CreateToolButtons()
2982 {
2983   int i;
2984
2985   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2986   {
2987     Bitmap *gd_bitmap = pix[PIX_DOOR];
2988     Bitmap *deco_bitmap = None;
2989     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2990     struct GadgetInfo *gi;
2991     unsigned long event_mask;
2992     int gd_xoffset, gd_yoffset;
2993     int gd_x1, gd_x2, gd_y;
2994     int id = i;
2995
2996     event_mask = GD_EVENT_RELEASED;
2997
2998     gd_xoffset = toolbutton_info[i].xpos;
2999     gd_yoffset = toolbutton_info[i].ypos;
3000     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3001     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3002     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3003
3004     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3005     {
3006       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
3007                            &deco_bitmap, &deco_x, &deco_y);
3008       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3009       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3010     }
3011
3012     gi = CreateGadget(GDI_CUSTOM_ID, id,
3013                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3014                       GDI_X, DX + toolbutton_info[i].x,
3015                       GDI_Y, DY + toolbutton_info[i].y,
3016                       GDI_WIDTH, toolbutton_info[i].width,
3017                       GDI_HEIGHT, toolbutton_info[i].height,
3018                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3019                       GDI_STATE, GD_BUTTON_UNPRESSED,
3020                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3021                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3022                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3023                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3024                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3025                       GDI_DECORATION_SHIFTING, 1, 1,
3026                       GDI_EVENT_MASK, event_mask,
3027                       GDI_CALLBACK_ACTION, HandleToolButtons,
3028                       GDI_END);
3029
3030     if (gi == NULL)
3031       Error(ERR_EXIT, "cannot create gadget");
3032
3033     tool_gadget[id] = gi;
3034   }
3035 }
3036
3037 static void UnmapToolButtons()
3038 {
3039   int i;
3040
3041   for (i=0; i<NUM_TOOL_BUTTONS; i++)
3042     UnmapGadget(tool_gadget[i]);
3043 }
3044
3045 static void HandleToolButtons(struct GadgetInfo *gi)
3046 {
3047   request_gadget_id = gi->custom_id;
3048 }
3049
3050 int get_next_element(int element)
3051 {
3052   switch(element)
3053   {
3054     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
3055     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
3056     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
3057     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
3058     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
3059     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
3060     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
3061
3062     default:                            return element;
3063   }
3064 }
3065
3066 int el2gfx_OLD(int element)
3067 {
3068   switch(element)
3069   {
3070     case EL_EMPTY:                      return -1;
3071     case EL_SAND:                       return GFX_ERDREICH;
3072     case EL_WALL:                       return GFX_MAUERWERK;
3073     case EL_WALL_CRUMBLED:              return GFX_FELSBODEN;
3074     case EL_ROCK:                       return GFX_FELSBROCKEN;
3075     case EL_EMERALD:                    return GFX_EDELSTEIN;
3076     case EL_EXIT_CLOSED:                return GFX_AUSGANG_ZU;
3077     case EL_EXIT_OPENING:               return GFX_AUSGANG_ACT;
3078     case EL_EXIT_OPEN:                  return GFX_AUSGANG_AUF;
3079     case EL_SP_EXIT_OPEN:               return GFX_SP_EXIT;
3080     case EL_PLAYER1:                    return GFX_SPIELER1;
3081     case EL_PLAYER2:                    return GFX_SPIELER2;
3082     case EL_PLAYER3:                    return GFX_SPIELER3;
3083     case EL_PLAYER4:                    return GFX_SPIELER4;
3084     case EL_BUG:                        return GFX_KAEFER;
3085     case EL_BUG_RIGHT:                  return GFX_KAEFER_RIGHT;
3086     case EL_BUG_UP:                     return GFX_KAEFER_UP;
3087     case EL_BUG_LEFT:                   return GFX_KAEFER_LEFT;
3088     case EL_BUG_DOWN:                   return GFX_KAEFER_DOWN;
3089     case EL_SPACESHIP:                  return GFX_FLIEGER;
3090     case EL_SPACESHIP_RIGHT:            return GFX_FLIEGER_RIGHT;
3091     case EL_SPACESHIP_UP:               return GFX_FLIEGER_UP;
3092     case EL_SPACESHIP_LEFT:             return GFX_FLIEGER_LEFT;
3093     case EL_SPACESHIP_DOWN:             return GFX_FLIEGER_DOWN;
3094     case EL_BD_BUTTERFLY:               return GFX_BUTTERFLY;
3095     case EL_BD_BUTTERFLY_RIGHT:         return GFX_BUTTERFLY_RIGHT;
3096     case EL_BD_BUTTERFLY_UP:            return GFX_BUTTERFLY_UP;
3097     case EL_BD_BUTTERFLY_LEFT:          return GFX_BUTTERFLY_LEFT;
3098     case EL_BD_BUTTERFLY_DOWN:          return GFX_BUTTERFLY_DOWN;
3099     case EL_BD_FIREFLY:                 return GFX_FIREFLY;
3100     case EL_BD_FIREFLY_RIGHT:           return GFX_FIREFLY_RIGHT;
3101     case EL_BD_FIREFLY_UP:              return GFX_FIREFLY_UP;
3102     case EL_BD_FIREFLY_LEFT:            return GFX_FIREFLY_LEFT;
3103     case EL_BD_FIREFLY_DOWN:            return GFX_FIREFLY_DOWN;
3104     case EL_YAMYAM:                     return GFX_MAMPFER;
3105     case EL_ROBOT:                      return GFX_ROBOT;
3106     case EL_STEELWALL:                  return GFX_BETON;
3107     case EL_DIAMOND:                    return GFX_DIAMANT;
3108     case EL_QUICKSAND_EMPTY:            return GFX_MORAST_LEER;
3109     case EL_QUICKSAND_FULL:             return GFX_MORAST_VOLL;
3110     case EL_QUICKSAND_EMPTYING:         return GFX_MORAST_LEER;
3111     case EL_AMOEBA_DROP:                return GFX_TROPFEN;
3112     case EL_BOMB:                       return GFX_BOMBE;
3113     case EL_MAGIC_WALL:                 return GFX_MAGIC_WALL_OFF;
3114     case EL_MAGIC_WALL_ACTIVE:          return GFX_MAGIC_WALL_EMPTY;
3115     case EL_MAGIC_WALL_EMPTYING:        return GFX_MAGIC_WALL_EMPTY;
3116     case EL_MAGIC_WALL_FULL:            return GFX_MAGIC_WALL_FULL;
3117     case EL_MAGIC_WALL_DEAD:            return GFX_MAGIC_WALL_DEAD;
3118     case EL_ACID:                       return GFX_SALZSAEURE;
3119     case EL_AMOEBA_DEAD:                return GFX_AMOEBE_TOT;
3120     case EL_AMOEBA_WET:                 return GFX_AMOEBE_NASS;
3121     case EL_AMOEBA_DRY:                 return GFX_AMOEBE_NORM;
3122     case EL_AMOEBA_FULL:                return GFX_AMOEBE_VOLL;
3123     case EL_BD_AMOEBA:                  return GFX_AMOEBE_BD;
3124     case EL_AMOEBA_TO_DIAMOND:          return GFX_AMOEBA2DIAM;
3125     case EL_AMOEBA_DRIPPING:            return GFX_AMOEBE_NASS;
3126     case EL_NUT:                        return GFX_KOKOSNUSS;
3127     case EL_GAMEOFLIFE:                 return GFX_LIFE;
3128     case EL_BIOMAZE:                    return GFX_LIFE_ASYNC;
3129     case EL_DYNAMITE_ACTIVE:            return GFX_DYNAMIT;
3130     case EL_STONEBLOCK:                 return GFX_BADEWANNE;
3131     case EL_ACIDPOOL_TOPLEFT:           return GFX_BADEWANNE1;
3132     case EL_ACIDPOOL_TOPRIGHT:          return GFX_BADEWANNE2;
3133     case EL_ACIDPOOL_BOTTOMLEFT:        return GFX_BADEWANNE3;
3134     case EL_ACIDPOOL_BOTTOM:            return GFX_BADEWANNE4;
3135     case EL_ACIDPOOL_BOTTOMRIGHT:       return GFX_BADEWANNE5;
3136     case EL_ROBOT_WHEEL:                return GFX_ABLENK_AUS;
3137     case EL_ROBOT_WHEEL_ACTIVE:         return GFX_ABLENK_EIN;
3138     case EL_KEY1:                       return GFX_SCHLUESSEL1;
3139     case EL_KEY2:                       return GFX_SCHLUESSEL2;
3140     case EL_KEY3:                       return GFX_SCHLUESSEL3;
3141     case EL_KEY4:                       return GFX_SCHLUESSEL4;
3142     case EL_GATE1:                      return GFX_PFORTE1;
3143     case EL_GATE2:                      return GFX_PFORTE2;
3144     case EL_GATE3:                      return GFX_PFORTE3;
3145     case EL_GATE4:                      return GFX_PFORTE4;
3146     case EL_GATE1_GRAY:                 return GFX_PFORTE1X;
3147     case EL_GATE2_GRAY:                 return GFX_PFORTE2X;
3148     case EL_GATE3_GRAY:                 return GFX_PFORTE3X;
3149     case EL_GATE4_GRAY:                 return GFX_PFORTE4X;
3150     case EL_DYNAMITE:                   return GFX_DYNAMIT_AUS;
3151     case EL_PACMAN:                     return GFX_PACMAN;
3152     case EL_PACMAN_RIGHT:               return GFX_PACMAN_RIGHT;
3153     case EL_PACMAN_UP:                  return GFX_PACMAN_UP;
3154     case EL_PACMAN_LEFT:                return GFX_PACMAN_LEFT;
3155     case EL_PACMAN_DOWN:                return GFX_PACMAN_DOWN;
3156     case EL_INVISIBLE_WALL:             return GFX_UNSICHTBAR;
3157     case EL_INVISIBLE_WALL_ACTIVE:      return GFX_UNSICHTBAR_ON;
3158     case EL_WALL_EMERALD:               return GFX_ERZ_EDEL;
3159     case EL_WALL_DIAMOND:               return GFX_ERZ_DIAM;
3160     case EL_LAMP:                       return GFX_BIRNE_AUS;
3161     case EL_LAMP_ACTIVE:                return GFX_BIRNE_EIN;
3162     case EL_TIME_ORB_FULL:              return GFX_ZEIT_VOLL;
3163     case EL_TIME_ORB_EMPTY:             return GFX_ZEIT_LEER;
3164     case EL_WALL_GROWING:               return GFX_MAUER_LEBT;
3165     case EL_WALL_GROWING_X:             return GFX_MAUER_X;
3166     case EL_WALL_GROWING_Y:             return GFX_MAUER_Y;
3167     case EL_WALL_GROWING_XY:            return GFX_MAUER_XY;
3168     case EL_BD_DIAMOND:                 return GFX_EDELSTEIN_BD;
3169     case EL_EMERALD_YELLOW:             return GFX_EDELSTEIN_GELB;
3170     case EL_EMERALD_RED:                return GFX_EDELSTEIN_ROT;
3171     case EL_EMERALD_PURPLE:             return GFX_EDELSTEIN_LILA;
3172     case EL_WALL_BD_DIAMOND:            return GFX_ERZ_EDEL_BD;
3173     case EL_WALL_EMERALD_YELLOW:        return GFX_ERZ_EDEL_GELB;
3174     case EL_WALL_EMERALD_RED:           return GFX_ERZ_EDEL_ROT;
3175     case EL_WALL_EMERALD_PURPLE:        return GFX_ERZ_EDEL_LILA;
3176     case EL_DARK_YAMYAM:                return GFX_MAMPFER2;
3177     case EL_BD_MAGIC_WALL:              return GFX_MAGIC_WALL_BD_OFF;
3178     case EL_BD_MAGIC_WALL_ACTIVE:       return GFX_MAGIC_WALL_BD_EMPTY;
3179     case EL_BD_MAGIC_WALL_EMPTYING:     return GFX_MAGIC_WALL_BD_EMPTY;
3180     case EL_BD_MAGIC_WALL_FULL:         return GFX_MAGIC_WALL_BD_FULL;
3181     case EL_BD_MAGIC_WALL_DEAD:         return GFX_MAGIC_WALL_BD_DEAD;
3182     case EL_DYNABOMB_PLAYER1_ACTIVE:    return GFX_DYNABOMB;
3183     case EL_DYNABOMB_PLAYER2_ACTIVE:    return GFX_DYNABOMB;
3184     case EL_DYNABOMB_PLAYER3_ACTIVE:    return GFX_DYNABOMB;
3185     case EL_DYNABOMB_PLAYER4_ACTIVE:    return GFX_DYNABOMB;
3186     case EL_DYNABOMB_NR:                return GFX_DYNABOMB_NR;
3187     case EL_DYNABOMB_SZ:                return GFX_DYNABOMB_SZ;
3188     case EL_DYNABOMB_XL:                return GFX_DYNABOMB_XL;
3189     case EL_SOKOBAN_OBJECT:             return GFX_SOKOBAN_OBJEKT;
3190     case EL_SOKOBAN_FIELD_EMPTY:        return GFX_SOKOBAN_FELD_LEER;
3191     case EL_SOKOBAN_FIELD_FULL:         return GFX_SOKOBAN_FELD_VOLL;
3192     case EL_MOLE:                       return GFX_MOLE;
3193     case EL_PENGUIN:                    return GFX_PINGUIN;
3194     case EL_PIG:                        return GFX_SCHWEIN;
3195     case EL_DRAGON:                     return GFX_DRACHE;
3196     case EL_SATELLITE:                  return GFX_SONDE;
3197     case EL_ARROW_BLUE_LEFT:            return GFX_PFEIL_LEFT;
3198     case EL_ARROW_BLUE_RIGHT:           return GFX_PFEIL_RIGHT;
3199     case EL_ARROW_BLUE_UP:              return GFX_PFEIL_UP;
3200     case EL_ARROW_BLUE_DOWN:            return GFX_PFEIL_DOWN;
3201     case EL_SPEED_PILL:                 return GFX_SPEED_PILL;
3202     case EL_SP_TERMINAL_ACTIVE:         return GFX_SP_TERMINAL;
3203     case EL_SP_BUGGY_BASE_ACTIVE:       return GFX_SP_BUG_ACTIVE;
3204     case EL_SP_ZONK:                    return GFX_SP_ZONK;
3205       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
3206     case EL_INVISIBLE_STEELWALL:        return GFX_INVISIBLE_STEEL;
3207     case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
3208     case EL_BLACK_ORB:                  return GFX_BLACK_ORB;
3209     case EL_EM_GATE1:                   return GFX_EM_GATE_1;
3210     case EL_EM_GATE2:                   return GFX_EM_GATE_2;
3211     case EL_EM_GATE3:                   return GFX_EM_GATE_3;
3212     case EL_EM_GATE4:                   return GFX_EM_GATE_4;
3213     case EL_EM_GATE1_GRAY:              return GFX_EM_GATE_1X;
3214     case EL_EM_GATE2_GRAY:              return GFX_EM_GATE_2X;
3215     case EL_EM_GATE3_GRAY:              return GFX_EM_GATE_3X;
3216     case EL_EM_GATE4_GRAY:              return GFX_EM_GATE_4X;
3217     case EL_EM_KEY1_FILE:               return GFX_EM_KEY_1;
3218     case EL_EM_KEY2_FILE:               return GFX_EM_KEY_2;
3219     case EL_EM_KEY3_FILE:               return GFX_EM_KEY_3;
3220     case EL_EM_KEY4_FILE:               return GFX_EM_KEY_4;
3221     case EL_EM_KEY1:                    return GFX_EM_KEY_1;
3222     case EL_EM_KEY2:                    return GFX_EM_KEY_2;
3223     case EL_EM_KEY3:                    return GFX_EM_KEY_3;
3224     case EL_EM_KEY4:                    return GFX_EM_KEY_4;
3225     case EL_PEARL:                      return GFX_PEARL;
3226     case EL_CRYSTAL:                    return GFX_CRYSTAL;
3227     case EL_WALL_PEARL:                 return GFX_WALL_PEARL;
3228     case EL_WALL_CRYSTAL:               return GFX_WALL_CRYSTAL;
3229     case EL_DOOR_WHITE:                 return GFX_DOOR_WHITE;
3230     case EL_DOOR_WHITE_GRAY:            return GFX_DOOR_WHITE_GRAY;
3231     case EL_KEY_WHITE:                  return GFX_KEY_WHITE;
3232     case EL_SHIELD_NORMAL:              return GFX_SHIELD_PASSIVE;
3233     case EL_SHIELD_DEADLY:              return GFX_SHIELD_ACTIVE;
3234     case EL_EXTRA_TIME:                 return GFX_EXTRA_TIME;
3235     case EL_SWITCHGATE_OPEN:            return GFX_SWITCHGATE_OPEN;
3236     case EL_SWITCHGATE_CLOSED:          return GFX_SWITCHGATE_CLOSED;
3237     case EL_SWITCHGATE_SWITCH_UP:       return GFX_SWITCHGATE_SWITCH_1;
3238     case EL_SWITCHGATE_SWITCH_DOWN:     return GFX_SWITCHGATE_SWITCH_2;
3239     case EL_CONVEYOR_BELT1_LEFT:        return GFX_BELT1_LEFT;
3240     case EL_CONVEYOR_BELT1_MIDDLE:      return GFX_BELT1_MIDDLE;
3241     case EL_CONVEYOR_BELT1_RIGHT:       return GFX_BELT1_RIGHT;
3242     case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
3243     case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
3244     case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
3245     case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
3246     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
3247     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
3248     case EL_CONVEYOR_BELT2_LEFT:        return GFX_BELT2_LEFT;
3249     case EL_CONVEYOR_BELT2_MIDDLE:      return GFX_BELT2_MIDDLE;
3250     case EL_CONVEYOR_BELT2_RIGHT:       return GFX_BELT2_RIGHT;
3251     case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
3252     case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
3253     case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
3254     case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
3255     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
3256     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
3257     case EL_CONVEYOR_BELT3_LEFT:        return GFX_BELT3_LEFT;
3258     case EL_CONVEYOR_BELT3_MIDDLE:      return GFX_BELT3_MIDDLE;
3259     case EL_CONVEYOR_BELT3_RIGHT:       return GFX_BELT3_RIGHT;
3260     case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
3261     case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
3262     case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
3263     case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
3264     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
3265     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
3266     case EL_CONVEYOR_BELT4_LEFT:        return GFX_BELT4_LEFT;
3267     case EL_CONVEYOR_BELT4_MIDDLE:      return GFX_BELT4_MIDDLE;
3268     case EL_CONVEYOR_BELT4_RIGHT:       return GFX_BELT4_RIGHT;
3269     case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
3270     case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
3271     case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
3272     case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
3273     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
3274     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
3275     case EL_LANDMINE:                   return GFX_LANDMINE;
3276     case EL_ENVELOPE:                   return GFX_ENVELOPE;
3277     case EL_LIGHT_SWITCH:               return GFX_LIGHT_SWITCH_OFF;
3278     case EL_LIGHT_SWITCH_ACTIVE:        return GFX_LIGHT_SWITCH_ON;
3279     case EL_SIGN_EXCLAMATION:           return GFX_SIGN_EXCLAMATION;
3280     case EL_SIGN_RADIOACTIVITY:         return GFX_SIGN_RADIOACTIVITY;
3281     case EL_SIGN_STOP:                  return GFX_SIGN_STOP;
3282     case EL_SIGN_WHEELCHAIR:            return GFX_SIGN_WHEELCHAIR;
3283     case EL_SIGN_PARKING:               return GFX_SIGN_PARKING;
3284     case EL_SIGN_ONEWAY:                return GFX_SIGN_ONEWAY;
3285     case EL_SIGN_HEART:                 return GFX_SIGN_HEART;
3286     case EL_SIGN_TRIANGLE:              return GFX_SIGN_TRIANGLE;
3287     case EL_SIGN_ROUND:                 return GFX_SIGN_ROUND;
3288     case EL_SIGN_EXIT:                  return GFX_SIGN_EXIT;
3289     case EL_SIGN_YINYANG:               return GFX_SIGN_YINYANG;
3290     case EL_SIGN_OTHER:                 return GFX_SIGN_OTHER;
3291     case EL_MOLE_LEFT:                  return GFX_MOLE_LEFT;
3292     case EL_MOLE_RIGHT:                 return GFX_MOLE_RIGHT;
3293     case EL_MOLE_UP:                    return GFX_MOLE_UP;
3294     case EL_MOLE_DOWN:                  return GFX_MOLE_DOWN;
3295     case EL_STEELWALL_SLANTED:          return GFX_STEEL_SLANTED;
3296     case EL_INVISIBLE_SAND:             return GFX_SAND_INVISIBLE;
3297     case EL_INVISIBLE_SAND_ACTIVE:      return GFX_SAND_INVISIBLE_ON;
3298     case EL_DX_UNKNOWN_15:              return GFX_DX_UNKNOWN_15;
3299     case EL_DX_UNKNOWN_42:              return GFX_DX_UNKNOWN_42;
3300     case EL_TIMEGATE_OPEN:              return GFX_TIMEGATE_OPEN;
3301     case EL_TIMEGATE_CLOSED:            return GFX_TIMEGATE_CLOSED;
3302     case EL_TIMEGATE_SWITCH_ACTIVE:     return GFX_TIMEGATE_SWITCH;
3303     case EL_TIMEGATE_SWITCH:            return GFX_TIMEGATE_SWITCH;
3304     case EL_BALLOON:                    return GFX_BALLOON;
3305     case EL_BALLOON_SEND_LEFT:          return GFX_BALLOON_SEND_LEFT;
3306     case EL_BALLOON_SEND_RIGHT:         return GFX_BALLOON_SEND_RIGHT;
3307     case EL_BALLOON_SEND_UP:            return GFX_BALLOON_SEND_UP;
3308     case EL_BALLOON_SEND_DOWN:          return GFX_BALLOON_SEND_DOWN;
3309     case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
3310     case EL_EMC_STEELWALL1:             return GFX_EMC_STEEL_WALL_1;
3311     case EL_EMC_STEELWALL2:             return GFX_EMC_STEEL_WALL_2;
3312     case EL_EMC_STEELWALL3:             return GFX_EMC_STEEL_WALL_3;
3313     case EL_EMC_STEELWALL4:             return GFX_EMC_STEEL_WALL_4;
3314     case EL_EMC_WALL_PILLAR_UPPER:      return GFX_EMC_WALL_1;
3315     case EL_EMC_WALL_PILLAR_MIDDLE:     return GFX_EMC_WALL_2;
3316     case EL_EMC_WALL_PILLAR_LOWER:      return GFX_EMC_WALL_3;
3317     case EL_EMC_WALL4:                  return GFX_EMC_WALL_4;
3318     case EL_EMC_WALL5:                  return GFX_EMC_WALL_5;
3319     case EL_EMC_WALL6:                  return GFX_EMC_WALL_6;
3320     case EL_EMC_WALL7:                  return GFX_EMC_WALL_7;
3321     case EL_EMC_WALL8:                  return GFX_EMC_WALL_8;
3322     case EL_TUBE_ALL:                   return GFX_TUBE_CROSS;
3323     case EL_TUBE_VERTICAL:              return GFX_TUBE_VERTICAL;
3324     case EL_TUBE_HORIZONTAL:            return GFX_TUBE_HORIZONTAL;
3325     case EL_TUBE_VERTICAL_LEFT:         return GFX_TUBE_VERT_LEFT;
3326     case EL_TUBE_VERTICAL_RIGHT:        return GFX_TUBE_VERT_RIGHT;
3327     case EL_TUBE_HORIZONTAL_UP:         return GFX_TUBE_HORIZ_UP;
3328     case EL_TUBE_HORIZONTAL_DOWN:       return GFX_TUBE_HORIZ_DOWN;
3329     case EL_TUBE_LEFT_UP:               return GFX_TUBE_LEFT_UP;
3330     case EL_TUBE_LEFT_DOWN:             return GFX_TUBE_LEFT_DOWN;
3331     case EL_TUBE_RIGHT_UP:              return GFX_TUBE_RIGHT_UP;
3332     case EL_TUBE_RIGHT_DOWN:            return GFX_TUBE_RIGHT_DOWN;
3333     case EL_SPRING:                     return GFX_SPRING;
3334     case EL_SPRING_MOVING:              return GFX_SPRING;
3335     case EL_TRAP:                       return GFX_TRAP_INACTIVE;
3336     case EL_TRAP_ACTIVE:                return GFX_TRAP_ACTIVE;
3337     case EL_BD_WALL:                    return GFX_BD_WALL;
3338     case EL_BD_ROCK:                    return GFX_BD_ROCK;
3339     case EL_DX_SUPABOMB:                return GFX_DX_SUPABOMB;
3340     case EL_SP_MURPHY_CLONE:            return GFX_SP_MURPHY_CLONE;
3341
3342     default:
3343     {
3344       if (IS_CHAR(element))
3345         return GFX_CHAR_START + (element - EL_CHAR_START);
3346       else if (element >= EL_SP_START && element <= EL_SP_END)
3347       {
3348         int nr_element = element - EL_SP_START;
3349         int gfx_per_line = 8;
3350         int nr_graphic =
3351           (nr_element / gfx_per_line) * SP_PER_LINE +
3352           (nr_element % gfx_per_line);
3353
3354         return GFX_START_ROCKSSP + nr_graphic;
3355       }
3356       else
3357         return -1;
3358     }
3359   }
3360 }
3361
3362 int el2gfx(int element)
3363 {
3364 #if 1
3365   int graphic_OLD = el2gfx_OLD(element);
3366
3367   return graphic_OLD;
3368 #else
3369
3370   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
3371
3372 #if DEBUG
3373   int graphic_OLD = el2gfx_OLD(element);
3374
3375   if (element >= MAX_ELEMENTS)
3376   {
3377     Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
3378   }
3379
3380   if (graphic_NEW != graphic_OLD)
3381   {
3382     Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
3383           graphic_NEW, graphic_OLD);
3384   }
3385 #endif
3386
3387   return graphic_NEW;
3388 #endif
3389 }
3390
3391 int el2img(int element)
3392 {
3393 #if 1
3394   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
3395
3396 #if DEBUG
3397   if (graphic_NEW < 0)
3398     Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
3399           element, graphic_NEW);
3400 #endif
3401
3402   return graphic_NEW;
3403 #else
3404
3405   switch(element)
3406   {
3407     case EL_BD_BUTTERFLY:       return IMG_BD_BUTTERFLY;
3408     case EL_BD_FIREFLY:         return IMG_BD_FIREFLY;
3409     case EL_SP_ELECTRON:        return IMG_SP_ELECTRON;
3410
3411     default:
3412       break;
3413   }
3414
3415   return IMG_EMPTY;
3416 #endif
3417 }
3418
3419 int el_dir2img(int element, int direction)
3420 {
3421   return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
3422 }
3423
3424 int el_dir_act2img(int element, int direction, int action)
3425 {
3426   action = graphics_action_mapping[action];
3427   direction = MV_DIR_BIT(direction);
3428
3429   return element_info[element].direction_graphic[action][direction];
3430 }