63324e0a698788483c450aea5d0f51e56e5d42f2
[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 getNewMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
2200 {
2201   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
2202   int mini_startx = src_bitmap->width * 3 / 4;
2203   int mini_starty = src_bitmap->height * 2 / 3;
2204   int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
2205   int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
2206
2207   *bitmap = src_bitmap;
2208   *x = src_x;
2209   *y = src_y;
2210 }
2211
2212 void DrawNewMicroElement(int xpos, int ypos, int element)
2213 {
2214   Bitmap *src_bitmap;
2215   int src_x, src_y;
2216   int graphic;
2217
2218   if (element == EL_EMPTY)
2219     return;
2220
2221   graphic = el2img(element);
2222
2223   getNewMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
2224   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
2225              xpos, ypos);
2226 }
2227
2228 void DrawLevel()
2229 {
2230   int x,y;
2231
2232   ClearWindow();
2233
2234   for(x=BX1; x<=BX2; x++)
2235     for(y=BY1; y<=BY2; y++)
2236       DrawNewScreenField(x, y);
2237
2238   redraw_mask |= REDRAW_FIELD;
2239 }
2240
2241 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2242 {
2243   int x,y;
2244
2245   for(x=0; x<size_x; x++)
2246     for(y=0; y<size_y; y++)
2247       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2248
2249   redraw_mask |= REDRAW_FIELD;
2250 }
2251
2252 void DrawNewMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2253 {
2254   int x,y;
2255
2256   for(x=0; x<size_x; x++)
2257     for(y=0; y<size_y; y++)
2258       DrawNewMiniElementOrWall(x, y, scroll_x, scroll_y);
2259
2260   redraw_mask |= REDRAW_FIELD;
2261 }
2262
2263 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
2264 {
2265   int x, y;
2266
2267   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
2268
2269   if (lev_fieldx < STD_LEV_FIELDX)
2270     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
2271   if (lev_fieldy < STD_LEV_FIELDY)
2272     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
2273
2274   xpos += MICRO_TILEX;
2275   ypos += MICRO_TILEY;
2276
2277   for(x=-1; x<=STD_LEV_FIELDX; x++)
2278   {
2279     for(y=-1; y<=STD_LEV_FIELDY; y++)
2280     {
2281       int lx = from_x + x, ly = from_y + y;
2282
2283       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
2284         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2285                          Ur[lx][ly]);
2286       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
2287         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2288                          BorderElement);
2289     }
2290   }
2291
2292   redraw_mask |= REDRAW_MICROLEVEL;
2293 }
2294
2295 static void DrawNewMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
2296 {
2297   int x, y;
2298
2299   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
2300
2301   if (lev_fieldx < STD_LEV_FIELDX)
2302     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
2303   if (lev_fieldy < STD_LEV_FIELDY)
2304     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
2305
2306   xpos += MICRO_TILEX;
2307   ypos += MICRO_TILEY;
2308
2309   for(x=-1; x<=STD_LEV_FIELDX; x++)
2310   {
2311     for(y=-1; y<=STD_LEV_FIELDY; y++)
2312     {
2313       int lx = from_x + x, ly = from_y + y;
2314
2315       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
2316         DrawNewMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2317                             Ur[lx][ly]);
2318       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
2319         DrawNewMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
2320                             BorderElement);
2321     }
2322   }
2323
2324   redraw_mask |= REDRAW_MICROLEVEL;
2325 }
2326
2327 #define MICROLABEL_EMPTY                0
2328 #define MICROLABEL_LEVEL_NAME           1
2329 #define MICROLABEL_CREATED_BY           2
2330 #define MICROLABEL_LEVEL_AUTHOR         3
2331 #define MICROLABEL_IMPORTED_FROM        4
2332 #define MICROLABEL_LEVEL_IMPORT_INFO    5
2333
2334 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
2335
2336 static void DrawMicroLevelLabelExt(int mode)
2337 {
2338   char label_text[MAX_MICROLABEL_SIZE + 1];
2339
2340   ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
2341
2342   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
2343                        mode == MICROLABEL_CREATED_BY ? "created by" :
2344                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2345                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
2346                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
2347                        leveldir_current->imported_from : ""),
2348           MAX_MICROLABEL_SIZE);
2349   label_text[MAX_MICROLABEL_SIZE] = '\0';
2350
2351   if (strlen(label_text) > 0)
2352   {
2353     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
2354     int lypos = MICROLABEL_YPOS;
2355
2356     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
2357   }
2358
2359   redraw_mask |= REDRAW_MICROLEVEL;
2360 }
2361
2362 void DrawMicroLevel(int xpos, int ypos, boolean restart)
2363 {
2364   static unsigned long scroll_delay = 0;
2365   static unsigned long label_delay = 0;
2366   static int from_x, from_y, scroll_direction;
2367   static int label_state, label_counter;
2368
2369   if (restart)
2370   {
2371     from_x = from_y = 0;
2372     scroll_direction = MV_RIGHT;
2373     label_state = 1;
2374     label_counter = 0;
2375
2376     DrawNewMicroLevelExt(xpos, ypos, from_x, from_y);
2377     DrawMicroLevelLabelExt(label_state);
2378
2379     /* initialize delay counters */
2380     DelayReached(&scroll_delay, 0);
2381     DelayReached(&label_delay, 0);
2382
2383     return;
2384   }
2385
2386   /* scroll micro level, if needed */
2387   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
2388       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
2389   {
2390     switch (scroll_direction)
2391     {
2392       case MV_LEFT:
2393         if (from_x > 0)
2394           from_x--;
2395         else
2396           scroll_direction = MV_UP;
2397         break;
2398
2399       case MV_RIGHT:
2400         if (from_x < lev_fieldx - STD_LEV_FIELDX)
2401           from_x++;
2402         else
2403           scroll_direction = MV_DOWN;
2404         break;
2405
2406       case MV_UP:
2407         if (from_y > 0)
2408           from_y--;
2409         else
2410           scroll_direction = MV_RIGHT;
2411         break;
2412
2413       case MV_DOWN:
2414         if (from_y < lev_fieldy - STD_LEV_FIELDY)
2415           from_y++;
2416         else
2417           scroll_direction = MV_LEFT;
2418         break;
2419
2420       default:
2421         break;
2422     }
2423
2424     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
2425   }
2426
2427   /* redraw micro level label, if needed */
2428   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
2429       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
2430       strcmp(level.author, leveldir_current->name) != 0 &&
2431       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2432   {
2433     int max_label_counter = 23;
2434
2435     if (leveldir_current->imported_from != NULL)
2436       max_label_counter += 14;
2437
2438     label_counter = (label_counter + 1) % max_label_counter;
2439     label_state = (label_counter >= 0 && label_counter <= 7 ?
2440                    MICROLABEL_LEVEL_NAME :
2441                    label_counter >= 9 && label_counter <= 12 ?
2442                    MICROLABEL_CREATED_BY :
2443                    label_counter >= 14 && label_counter <= 21 ?
2444                    MICROLABEL_LEVEL_AUTHOR :
2445                    label_counter >= 23 && label_counter <= 26 ?
2446                    MICROLABEL_IMPORTED_FROM :
2447                    label_counter >= 28 && label_counter <= 35 ?
2448                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
2449     DrawMicroLevelLabelExt(label_state);
2450   }
2451 }
2452
2453 int REQ_in_range(int x, int y)
2454 {
2455   if (y > DY+249 && y < DY+278)
2456   {
2457     if (x > DX+1 && x < DX+48)
2458       return 1;
2459     else if (x > DX+51 && x < DX+98) 
2460       return 2;
2461   }
2462   return 0;
2463 }
2464
2465 #define MAX_REQUEST_LINES               13
2466 #define MAX_REQUEST_LINE_LEN            7
2467
2468 boolean Request(char *text, unsigned int req_state)
2469 {
2470   int mx, my, ty, result = -1;
2471   unsigned int old_door_state;
2472
2473 #if defined(PLATFORM_UNIX)
2474   /* pause network game while waiting for request to answer */
2475   if (options.network &&
2476       game_status == PLAYING &&
2477       req_state & REQUEST_WAIT_FOR)
2478     SendToServer_PausePlaying();
2479 #endif
2480
2481   old_door_state = GetDoorState();
2482
2483   UnmapAllGadgets();
2484
2485   CloseDoor(DOOR_CLOSE_1);
2486
2487   /* save old door content */
2488   BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2489              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2490              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2491
2492   /* clear door drawing field */
2493   ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
2494
2495   /* write text for request */
2496   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2497   {
2498     char text_line[MAX_REQUEST_LINE_LEN + 1];
2499     int tx, tl, tc;
2500
2501     if (!*text)
2502       break;
2503
2504     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2505     {
2506       tc = *(text + tx);
2507       if (!tc || tc == ' ')
2508         break;
2509     }
2510
2511     if (!tl)
2512     { 
2513       text++; 
2514       ty--; 
2515       continue; 
2516     }
2517
2518     strncpy(text_line, text, tl);
2519     text_line[tl] = 0;
2520
2521     DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
2522                 text_line, FS_SMALL, FC_YELLOW);
2523
2524     text += tl + (tc == ' ' ? 1 : 0);
2525   }
2526
2527   if (req_state & REQ_ASK)
2528   {
2529     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2530     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2531   }
2532   else if (req_state & REQ_CONFIRM)
2533   {
2534     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2535   }
2536   else if (req_state & REQ_PLAYER)
2537   {
2538     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2539     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2540     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2541     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2542   }
2543
2544   /* copy request gadgets to door backbuffer */
2545   BlitBitmap(drawto, pix[PIX_DB_DOOR],
2546              DX, DY, DXSIZE, DYSIZE,
2547              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2548
2549   OpenDoor(DOOR_OPEN_1);
2550
2551 #if 0
2552   ClearEventQueue();
2553 #endif
2554
2555   if (!(req_state & REQUEST_WAIT_FOR))
2556     return(FALSE);
2557
2558   if (game_status != MAINMENU)
2559     InitAnimation();
2560
2561   button_status = MB_RELEASED;
2562
2563   request_gadget_id = -1;
2564
2565   while(result < 0)
2566   {
2567     if (PendingEvent())
2568     {
2569       Event event;
2570
2571       NextEvent(&event);
2572
2573       switch(event.type)
2574       {
2575         case EVENT_BUTTONPRESS:
2576         case EVENT_BUTTONRELEASE:
2577         case EVENT_MOTIONNOTIFY:
2578         {
2579           if (event.type == EVENT_MOTIONNOTIFY)
2580           {
2581             if (!PointerInWindow(window))
2582               continue; /* window and pointer are on different screens */
2583
2584             if (!button_status)
2585               continue;
2586
2587             motion_status = TRUE;
2588             mx = ((MotionEvent *) &event)->x;
2589             my = ((MotionEvent *) &event)->y;
2590           }
2591           else
2592           {
2593             motion_status = FALSE;
2594             mx = ((ButtonEvent *) &event)->x;
2595             my = ((ButtonEvent *) &event)->y;
2596             if (event.type == EVENT_BUTTONPRESS)
2597               button_status = ((ButtonEvent *) &event)->button;
2598             else
2599               button_status = MB_RELEASED;
2600           }
2601
2602           /* this sets 'request_gadget_id' */
2603           HandleGadgets(mx, my, button_status);
2604
2605           switch(request_gadget_id)
2606           {
2607             case TOOL_CTRL_ID_YES:
2608               result = TRUE;
2609               break;
2610             case TOOL_CTRL_ID_NO:
2611               result = FALSE;
2612               break;
2613             case TOOL_CTRL_ID_CONFIRM:
2614               result = TRUE | FALSE;
2615               break;
2616
2617             case TOOL_CTRL_ID_PLAYER_1:
2618               result = 1;
2619               break;
2620             case TOOL_CTRL_ID_PLAYER_2:
2621               result = 2;
2622               break;
2623             case TOOL_CTRL_ID_PLAYER_3:
2624               result = 3;
2625               break;
2626             case TOOL_CTRL_ID_PLAYER_4:
2627               result = 4;
2628               break;
2629
2630             default:
2631               break;
2632           }
2633
2634           break;
2635         }
2636
2637         case EVENT_KEYPRESS:
2638           switch(GetEventKey((KeyEvent *)&event, TRUE))
2639           {
2640             case KSYM_Return:
2641               result = 1;
2642               break;
2643
2644             case KSYM_Escape:
2645               result = 0;
2646               break;
2647
2648             default:
2649               break;
2650           }
2651           if (req_state & REQ_PLAYER)
2652             result = 0;
2653           break;
2654
2655         case EVENT_KEYRELEASE:
2656           ClearPlayerAction();
2657           break;
2658
2659         default:
2660           HandleOtherEvents(&event);
2661           break;
2662       }
2663     }
2664     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2665     {
2666       int joy = AnyJoystick();
2667
2668       if (joy & JOY_BUTTON_1)
2669         result = 1;
2670       else if (joy & JOY_BUTTON_2)
2671         result = 0;
2672     }
2673
2674     DoAnimation();
2675
2676     /* don't eat all CPU time */
2677     Delay(10);
2678   }
2679
2680   if (game_status != MAINMENU)
2681     StopAnimation();
2682
2683   UnmapToolButtons();
2684
2685   if (!(req_state & REQ_STAY_OPEN))
2686   {
2687     CloseDoor(DOOR_CLOSE_1);
2688
2689     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2690     {
2691       BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2692                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2693                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2694       OpenDoor(DOOR_OPEN_1);
2695     }
2696   }
2697
2698   RemapAllGadgets();
2699
2700 #if defined(PLATFORM_UNIX)
2701   /* continue network game after request */
2702   if (options.network &&
2703       game_status == PLAYING &&
2704       req_state & REQUEST_WAIT_FOR)
2705     SendToServer_ContinuePlaying();
2706 #endif
2707
2708   return(result);
2709 }
2710
2711 unsigned int OpenDoor(unsigned int door_state)
2712 {
2713   unsigned int new_door_state;
2714
2715   if (door_state & DOOR_COPY_BACK)
2716   {
2717     BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2718                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2719                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2720     door_state &= ~DOOR_COPY_BACK;
2721   }
2722
2723   new_door_state = MoveDoor(door_state);
2724
2725   return(new_door_state);
2726 }
2727
2728 unsigned int CloseDoor(unsigned int door_state)
2729 {
2730   unsigned int new_door_state;
2731
2732   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2733              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2734   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2735              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2736
2737   new_door_state = MoveDoor(door_state);
2738
2739   return(new_door_state);
2740 }
2741
2742 unsigned int GetDoorState()
2743 {
2744   return MoveDoor(DOOR_GET_STATE);
2745 }
2746
2747 unsigned int SetDoorState(unsigned int door_state)
2748 {
2749   return MoveDoor(door_state | DOOR_SET_STATE);
2750 }
2751
2752 unsigned int MoveDoor(unsigned int door_state)
2753 {
2754   static int door1 = DOOR_OPEN_1;
2755   static int door2 = DOOR_CLOSE_2;
2756   static unsigned long door_delay = 0;
2757   int x, start, stepsize = 2;
2758   unsigned long door_delay_value = stepsize * 5;
2759
2760   if (door_state == DOOR_GET_STATE)
2761     return(door1 | door2);
2762
2763   if (door_state & DOOR_SET_STATE)
2764   {
2765     if (door_state & DOOR_ACTION_1)
2766       door1 = door_state & DOOR_ACTION_1;
2767     if (door_state & DOOR_ACTION_2)
2768       door2 = door_state & DOOR_ACTION_2;
2769
2770     return(door1 | door2);
2771   }
2772
2773   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2774     door_state &= ~DOOR_OPEN_1;
2775   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2776     door_state &= ~DOOR_CLOSE_1;
2777   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2778     door_state &= ~DOOR_OPEN_2;
2779   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2780     door_state &= ~DOOR_CLOSE_2;
2781
2782   if (setup.quick_doors)
2783   {
2784     stepsize = 20;
2785     door_delay_value = 0;
2786     StopSound(SND_MENU_DOOR_OPENING);
2787     StopSound(SND_MENU_DOOR_CLOSING);
2788   }
2789
2790   if (door_state & DOOR_ACTION)
2791   {
2792     if (!(door_state & DOOR_NO_DELAY))
2793     {
2794       /* opening door sound has priority over simultaneously closing door */
2795       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2796         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2797       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2798         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2799     }
2800
2801     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2802
2803     for(x=start; x<=DXSIZE; x+=stepsize)
2804     {
2805       Bitmap *bitmap = pix[PIX_DOOR];
2806       GC gc = bitmap->stored_clip_gc;
2807
2808       WaitUntilDelayReached(&door_delay, door_delay_value);
2809
2810       if (door_state & DOOR_ACTION_1)
2811       {
2812         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2813         int j = (DXSIZE - i) / 3;
2814
2815         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2816                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2817                    DXSIZE,DYSIZE - i/2, DX, DY);
2818
2819         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2820
2821         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2822         BlitBitmapMasked(bitmap, drawto,
2823                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2824                          DX + DXSIZE - i, DY + j);
2825         BlitBitmapMasked(bitmap, drawto,
2826                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2827                          DX + DXSIZE - i, DY + 140 + j);
2828         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2829         BlitBitmapMasked(bitmap, drawto,
2830                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2831                          DX, DY);
2832         BlitBitmapMasked(bitmap, drawto,
2833                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2834                          DX, DY + 140 - j);
2835
2836         BlitBitmapMasked(bitmap, drawto,
2837                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2838                          DX, DY + 77 - j);
2839         BlitBitmapMasked(bitmap, drawto,
2840                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2841                          DX, DY + 203 - j);
2842         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2843         BlitBitmapMasked(bitmap, drawto,
2844                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2845                          DX + DXSIZE - i, DY + 77 + j);
2846         BlitBitmapMasked(bitmap, drawto,
2847                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2848                          DX + DXSIZE - i, DY + 203 + j);
2849
2850         redraw_mask |= REDRAW_DOOR_1;
2851       }
2852
2853       if (door_state & DOOR_ACTION_2)
2854       {
2855         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2856         int j = (VXSIZE - i) / 3;
2857
2858         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2859                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2860                    VXSIZE, VYSIZE - i/2, VX, VY);
2861
2862         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2863
2864         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2865         BlitBitmapMasked(bitmap, drawto,
2866                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2867                          VX + VXSIZE-i, VY+j);
2868         SetClipOrigin(bitmap, gc,
2869                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2870         BlitBitmapMasked(bitmap, drawto,
2871                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2872                          VX, VY);
2873
2874         BlitBitmapMasked(bitmap, drawto,
2875                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2876                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2877         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2878         BlitBitmapMasked(bitmap, drawto,
2879                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2880                          i, VYSIZE / 2 - j,
2881                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2882
2883         redraw_mask |= REDRAW_DOOR_2;
2884       }
2885
2886       BackToFront();
2887
2888       if (game_status == MAINMENU)
2889         DoAnimation();
2890     }
2891   }
2892
2893   if (setup.quick_doors)
2894   {
2895     StopSound(SND_MENU_DOOR_OPENING);
2896     StopSound(SND_MENU_DOOR_CLOSING);
2897   }
2898
2899   if (door_state & DOOR_ACTION_1)
2900     door1 = door_state & DOOR_ACTION_1;
2901   if (door_state & DOOR_ACTION_2)
2902     door2 = door_state & DOOR_ACTION_2;
2903
2904   return (door1 | door2);
2905 }
2906
2907 void DrawSpecialEditorDoor()
2908 {
2909   /* draw bigger toolbox window */
2910   BlitBitmap(pix[PIX_DOOR], drawto,
2911              DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2912
2913   redraw_mask |= REDRAW_ALL;
2914 }
2915
2916 void UndrawSpecialEditorDoor()
2917 {
2918   /* draw normal tape recorder window */
2919   BlitBitmap(pix[PIX_BACK], drawto,
2920              562, 344, 108, 56, EX - 4, EY - 12);
2921
2922   redraw_mask |= REDRAW_ALL;
2923 }
2924
2925 #ifndef TARGET_SDL
2926 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2927 {
2928   XImage *pixel_image;
2929   unsigned long pixel_value;
2930
2931   pixel_image = XGetImage(display, bitmap->drawable,
2932                           x, y, 1, 1, AllPlanes, ZPixmap);
2933   pixel_value = XGetPixel(pixel_image, 0, 0);
2934
2935   XDestroyImage(pixel_image);
2936
2937   return pixel_value;
2938 }
2939 #endif
2940
2941 /* ---------- new tool button stuff ---------------------------------------- */
2942
2943 /* graphic position values for tool buttons */
2944 #define TOOL_BUTTON_YES_XPOS            2
2945 #define TOOL_BUTTON_YES_YPOS            250
2946 #define TOOL_BUTTON_YES_GFX_YPOS        0
2947 #define TOOL_BUTTON_YES_XSIZE           46
2948 #define TOOL_BUTTON_YES_YSIZE           28
2949 #define TOOL_BUTTON_NO_XPOS             52
2950 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2951 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2952 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2953 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2954 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2955 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2956 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2957 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2958 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2959 #define TOOL_BUTTON_PLAYER_XSIZE        30
2960 #define TOOL_BUTTON_PLAYER_YSIZE        30
2961 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2962 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2963 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2964 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2965 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2966                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2967 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2968                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2969 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2970                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2971 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2972                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2973 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2974                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2975 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2976                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2977 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2978                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2979 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2980                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2981
2982 static struct
2983 {
2984   int xpos, ypos;
2985   int x, y;
2986   int width, height;
2987   int gadget_id;
2988   char *infotext;
2989 } toolbutton_info[NUM_TOOL_BUTTONS] =
2990 {
2991   {
2992     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2993     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2994     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2995     TOOL_CTRL_ID_YES,
2996     "yes"
2997   },
2998   {
2999     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3000     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3001     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3002     TOOL_CTRL_ID_NO,
3003     "no"
3004   },
3005   {
3006     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3007     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3008     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3009     TOOL_CTRL_ID_CONFIRM,
3010     "confirm"
3011   },
3012   {
3013     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3014     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3015     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3016     TOOL_CTRL_ID_PLAYER_1,
3017     "player 1"
3018   },
3019   {
3020     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3021     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3022     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3023     TOOL_CTRL_ID_PLAYER_2,
3024     "player 2"
3025   },
3026   {
3027     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3028     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3029     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3030     TOOL_CTRL_ID_PLAYER_3,
3031     "player 3"
3032   },
3033   {
3034     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3035     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3036     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3037     TOOL_CTRL_ID_PLAYER_4,
3038     "player 4"
3039   }
3040 };
3041
3042 void CreateToolButtons()
3043 {
3044   int i;
3045
3046   for (i=0; i<NUM_TOOL_BUTTONS; i++)
3047   {
3048     Bitmap *gd_bitmap = pix[PIX_DOOR];
3049     Bitmap *deco_bitmap = None;
3050     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3051     struct GadgetInfo *gi;
3052     unsigned long event_mask;
3053     int gd_xoffset, gd_yoffset;
3054     int gd_x1, gd_x2, gd_y;
3055     int id = i;
3056
3057     event_mask = GD_EVENT_RELEASED;
3058
3059     gd_xoffset = toolbutton_info[i].xpos;
3060     gd_yoffset = toolbutton_info[i].ypos;
3061     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3062     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3063     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3064
3065     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3066     {
3067       getMiniGraphicSource(GFX_SPIELER1 + id - TOOL_CTRL_ID_PLAYER_1,
3068                            &deco_bitmap, &deco_x, &deco_y);
3069       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3070       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3071     }
3072
3073     gi = CreateGadget(GDI_CUSTOM_ID, id,
3074                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3075                       GDI_X, DX + toolbutton_info[i].x,
3076                       GDI_Y, DY + toolbutton_info[i].y,
3077                       GDI_WIDTH, toolbutton_info[i].width,
3078                       GDI_HEIGHT, toolbutton_info[i].height,
3079                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3080                       GDI_STATE, GD_BUTTON_UNPRESSED,
3081                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3082                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3083                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3084                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3085                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3086                       GDI_DECORATION_SHIFTING, 1, 1,
3087                       GDI_EVENT_MASK, event_mask,
3088                       GDI_CALLBACK_ACTION, HandleToolButtons,
3089                       GDI_END);
3090
3091     if (gi == NULL)
3092       Error(ERR_EXIT, "cannot create gadget");
3093
3094     tool_gadget[id] = gi;
3095   }
3096 }
3097
3098 static void UnmapToolButtons()
3099 {
3100   int i;
3101
3102   for (i=0; i<NUM_TOOL_BUTTONS; i++)
3103     UnmapGadget(tool_gadget[i]);
3104 }
3105
3106 static void HandleToolButtons(struct GadgetInfo *gi)
3107 {
3108   request_gadget_id = gi->custom_id;
3109 }
3110
3111 int get_next_element(int element)
3112 {
3113   switch(element)
3114   {
3115     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
3116     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
3117     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
3118     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
3119     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
3120     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
3121     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
3122
3123     default:                            return element;
3124   }
3125 }
3126
3127 int el2gfx_OLD(int element)
3128 {
3129   switch(element)
3130   {
3131     case EL_EMPTY:                      return -1;
3132     case EL_SAND:                       return GFX_ERDREICH;
3133     case EL_WALL:                       return GFX_MAUERWERK;
3134     case EL_WALL_CRUMBLED:              return GFX_FELSBODEN;
3135     case EL_ROCK:                       return GFX_FELSBROCKEN;
3136     case EL_EMERALD:                    return GFX_EDELSTEIN;
3137     case EL_EXIT_CLOSED:                return GFX_AUSGANG_ZU;
3138     case EL_EXIT_OPENING:               return GFX_AUSGANG_ACT;
3139     case EL_EXIT_OPEN:                  return GFX_AUSGANG_AUF;
3140     case EL_SP_EXIT_OPEN:               return GFX_SP_EXIT;
3141     case EL_PLAYER1:                    return GFX_SPIELER1;
3142     case EL_PLAYER2:                    return GFX_SPIELER2;
3143     case EL_PLAYER3:                    return GFX_SPIELER3;
3144     case EL_PLAYER4:                    return GFX_SPIELER4;
3145     case EL_BUG:                        return GFX_KAEFER;
3146     case EL_BUG_RIGHT:                  return GFX_KAEFER_RIGHT;
3147     case EL_BUG_UP:                     return GFX_KAEFER_UP;
3148     case EL_BUG_LEFT:                   return GFX_KAEFER_LEFT;
3149     case EL_BUG_DOWN:                   return GFX_KAEFER_DOWN;
3150     case EL_SPACESHIP:                  return GFX_FLIEGER;
3151     case EL_SPACESHIP_RIGHT:            return GFX_FLIEGER_RIGHT;
3152     case EL_SPACESHIP_UP:               return GFX_FLIEGER_UP;
3153     case EL_SPACESHIP_LEFT:             return GFX_FLIEGER_LEFT;
3154     case EL_SPACESHIP_DOWN:             return GFX_FLIEGER_DOWN;
3155     case EL_BD_BUTTERFLY:               return GFX_BUTTERFLY;
3156     case EL_BD_BUTTERFLY_RIGHT:         return GFX_BUTTERFLY_RIGHT;
3157     case EL_BD_BUTTERFLY_UP:            return GFX_BUTTERFLY_UP;
3158     case EL_BD_BUTTERFLY_LEFT:          return GFX_BUTTERFLY_LEFT;
3159     case EL_BD_BUTTERFLY_DOWN:          return GFX_BUTTERFLY_DOWN;
3160     case EL_BD_FIREFLY:                 return GFX_FIREFLY;
3161     case EL_BD_FIREFLY_RIGHT:           return GFX_FIREFLY_RIGHT;
3162     case EL_BD_FIREFLY_UP:              return GFX_FIREFLY_UP;
3163     case EL_BD_FIREFLY_LEFT:            return GFX_FIREFLY_LEFT;
3164     case EL_BD_FIREFLY_DOWN:            return GFX_FIREFLY_DOWN;
3165     case EL_YAMYAM:                     return GFX_MAMPFER;
3166     case EL_ROBOT:                      return GFX_ROBOT;
3167     case EL_STEELWALL:                  return GFX_BETON;
3168     case EL_DIAMOND:                    return GFX_DIAMANT;
3169     case EL_QUICKSAND_EMPTY:            return GFX_MORAST_LEER;
3170     case EL_QUICKSAND_FULL:             return GFX_MORAST_VOLL;
3171     case EL_QUICKSAND_EMPTYING:         return GFX_MORAST_LEER;
3172     case EL_AMOEBA_DROP:                return GFX_TROPFEN;
3173     case EL_BOMB:                       return GFX_BOMBE;
3174     case EL_MAGIC_WALL:                 return GFX_MAGIC_WALL_OFF;
3175     case EL_MAGIC_WALL_ACTIVE:          return GFX_MAGIC_WALL_EMPTY;
3176     case EL_MAGIC_WALL_EMPTYING:        return GFX_MAGIC_WALL_EMPTY;
3177     case EL_MAGIC_WALL_FULL:            return GFX_MAGIC_WALL_FULL;
3178     case EL_MAGIC_WALL_DEAD:            return GFX_MAGIC_WALL_DEAD;
3179     case EL_ACID:                       return GFX_SALZSAEURE;
3180     case EL_AMOEBA_DEAD:                return GFX_AMOEBE_TOT;
3181     case EL_AMOEBA_WET:                 return GFX_AMOEBE_NASS;
3182     case EL_AMOEBA_DRY:                 return GFX_AMOEBE_NORM;
3183     case EL_AMOEBA_FULL:                return GFX_AMOEBE_VOLL;
3184     case EL_BD_AMOEBA:                  return GFX_AMOEBE_BD;
3185     case EL_AMOEBA_TO_DIAMOND:          return GFX_AMOEBA2DIAM;
3186     case EL_AMOEBA_DRIPPING:            return GFX_AMOEBE_NASS;
3187     case EL_NUT:                        return GFX_KOKOSNUSS;
3188     case EL_GAMEOFLIFE:                 return GFX_LIFE;
3189     case EL_BIOMAZE:                    return GFX_LIFE_ASYNC;
3190     case EL_DYNAMITE_ACTIVE:            return GFX_DYNAMIT;
3191     case EL_STONEBLOCK:                 return GFX_BADEWANNE;
3192     case EL_ACIDPOOL_TOPLEFT:           return GFX_BADEWANNE1;
3193     case EL_ACIDPOOL_TOPRIGHT:          return GFX_BADEWANNE2;
3194     case EL_ACIDPOOL_BOTTOMLEFT:        return GFX_BADEWANNE3;
3195     case EL_ACIDPOOL_BOTTOM:            return GFX_BADEWANNE4;
3196     case EL_ACIDPOOL_BOTTOMRIGHT:       return GFX_BADEWANNE5;
3197     case EL_ROBOT_WHEEL:                return GFX_ABLENK_AUS;
3198     case EL_ROBOT_WHEEL_ACTIVE:         return GFX_ABLENK_EIN;
3199     case EL_KEY1:                       return GFX_SCHLUESSEL1;
3200     case EL_KEY2:                       return GFX_SCHLUESSEL2;
3201     case EL_KEY3:                       return GFX_SCHLUESSEL3;
3202     case EL_KEY4:                       return GFX_SCHLUESSEL4;
3203     case EL_GATE1:                      return GFX_PFORTE1;
3204     case EL_GATE2:                      return GFX_PFORTE2;
3205     case EL_GATE3:                      return GFX_PFORTE3;
3206     case EL_GATE4:                      return GFX_PFORTE4;
3207     case EL_GATE1_GRAY:                 return GFX_PFORTE1X;
3208     case EL_GATE2_GRAY:                 return GFX_PFORTE2X;
3209     case EL_GATE3_GRAY:                 return GFX_PFORTE3X;
3210     case EL_GATE4_GRAY:                 return GFX_PFORTE4X;
3211     case EL_DYNAMITE:                   return GFX_DYNAMIT_AUS;
3212     case EL_PACMAN:                     return GFX_PACMAN;
3213     case EL_PACMAN_RIGHT:               return GFX_PACMAN_RIGHT;
3214     case EL_PACMAN_UP:                  return GFX_PACMAN_UP;
3215     case EL_PACMAN_LEFT:                return GFX_PACMAN_LEFT;
3216     case EL_PACMAN_DOWN:                return GFX_PACMAN_DOWN;
3217     case EL_INVISIBLE_WALL:             return GFX_UNSICHTBAR;
3218     case EL_INVISIBLE_WALL_ACTIVE:      return GFX_UNSICHTBAR_ON;
3219     case EL_WALL_EMERALD:               return GFX_ERZ_EDEL;
3220     case EL_WALL_DIAMOND:               return GFX_ERZ_DIAM;
3221     case EL_LAMP:                       return GFX_BIRNE_AUS;
3222     case EL_LAMP_ACTIVE:                return GFX_BIRNE_EIN;
3223     case EL_TIME_ORB_FULL:              return GFX_ZEIT_VOLL;
3224     case EL_TIME_ORB_EMPTY:             return GFX_ZEIT_LEER;
3225     case EL_WALL_GROWING:               return GFX_MAUER_LEBT;
3226     case EL_WALL_GROWING_X:             return GFX_MAUER_X;
3227     case EL_WALL_GROWING_Y:             return GFX_MAUER_Y;
3228     case EL_WALL_GROWING_XY:            return GFX_MAUER_XY;
3229     case EL_BD_DIAMOND:                 return GFX_EDELSTEIN_BD;
3230     case EL_EMERALD_YELLOW:             return GFX_EDELSTEIN_GELB;
3231     case EL_EMERALD_RED:                return GFX_EDELSTEIN_ROT;
3232     case EL_EMERALD_PURPLE:             return GFX_EDELSTEIN_LILA;
3233     case EL_WALL_BD_DIAMOND:            return GFX_ERZ_EDEL_BD;
3234     case EL_WALL_EMERALD_YELLOW:        return GFX_ERZ_EDEL_GELB;
3235     case EL_WALL_EMERALD_RED:           return GFX_ERZ_EDEL_ROT;
3236     case EL_WALL_EMERALD_PURPLE:        return GFX_ERZ_EDEL_LILA;
3237     case EL_DARK_YAMYAM:                return GFX_MAMPFER2;
3238     case EL_BD_MAGIC_WALL:              return GFX_MAGIC_WALL_BD_OFF;
3239     case EL_BD_MAGIC_WALL_ACTIVE:       return GFX_MAGIC_WALL_BD_EMPTY;
3240     case EL_BD_MAGIC_WALL_EMPTYING:     return GFX_MAGIC_WALL_BD_EMPTY;
3241     case EL_BD_MAGIC_WALL_FULL:         return GFX_MAGIC_WALL_BD_FULL;
3242     case EL_BD_MAGIC_WALL_DEAD:         return GFX_MAGIC_WALL_BD_DEAD;
3243     case EL_DYNABOMB_PLAYER1_ACTIVE:    return GFX_DYNABOMB;
3244     case EL_DYNABOMB_PLAYER2_ACTIVE:    return GFX_DYNABOMB;
3245     case EL_DYNABOMB_PLAYER3_ACTIVE:    return GFX_DYNABOMB;
3246     case EL_DYNABOMB_PLAYER4_ACTIVE:    return GFX_DYNABOMB;
3247     case EL_DYNABOMB_NR:                return GFX_DYNABOMB_NR;
3248     case EL_DYNABOMB_SZ:                return GFX_DYNABOMB_SZ;
3249     case EL_DYNABOMB_XL:                return GFX_DYNABOMB_XL;
3250     case EL_SOKOBAN_OBJECT:             return GFX_SOKOBAN_OBJEKT;
3251     case EL_SOKOBAN_FIELD_EMPTY:        return GFX_SOKOBAN_FELD_LEER;
3252     case EL_SOKOBAN_FIELD_FULL:         return GFX_SOKOBAN_FELD_VOLL;
3253     case EL_MOLE:                       return GFX_MOLE;
3254     case EL_PENGUIN:                    return GFX_PINGUIN;
3255     case EL_PIG:                        return GFX_SCHWEIN;
3256     case EL_DRAGON:                     return GFX_DRACHE;
3257     case EL_SATELLITE:                  return GFX_SONDE;
3258     case EL_ARROW_BLUE_LEFT:            return GFX_PFEIL_LEFT;
3259     case EL_ARROW_BLUE_RIGHT:           return GFX_PFEIL_RIGHT;
3260     case EL_ARROW_BLUE_UP:              return GFX_PFEIL_UP;
3261     case EL_ARROW_BLUE_DOWN:            return GFX_PFEIL_DOWN;
3262     case EL_SPEED_PILL:                 return GFX_SPEED_PILL;
3263     case EL_SP_TERMINAL_ACTIVE:         return GFX_SP_TERMINAL;
3264     case EL_SP_BUGGY_BASE_ACTIVE:       return GFX_SP_BUG_ACTIVE;
3265     case EL_SP_ZONK:                    return GFX_SP_ZONK;
3266       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
3267     case EL_INVISIBLE_STEELWALL:        return GFX_INVISIBLE_STEEL;
3268     case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
3269     case EL_BLACK_ORB:                  return GFX_BLACK_ORB;
3270     case EL_EM_GATE1:                   return GFX_EM_GATE_1;
3271     case EL_EM_GATE2:                   return GFX_EM_GATE_2;
3272     case EL_EM_GATE3:                   return GFX_EM_GATE_3;
3273     case EL_EM_GATE4:                   return GFX_EM_GATE_4;
3274     case EL_EM_GATE1_GRAY:              return GFX_EM_GATE_1X;
3275     case EL_EM_GATE2_GRAY:              return GFX_EM_GATE_2X;
3276     case EL_EM_GATE3_GRAY:              return GFX_EM_GATE_3X;
3277     case EL_EM_GATE4_GRAY:              return GFX_EM_GATE_4X;
3278     case EL_EM_KEY1_FILE:               return GFX_EM_KEY_1;
3279     case EL_EM_KEY2_FILE:               return GFX_EM_KEY_2;
3280     case EL_EM_KEY3_FILE:               return GFX_EM_KEY_3;
3281     case EL_EM_KEY4_FILE:               return GFX_EM_KEY_4;
3282     case EL_EM_KEY1:                    return GFX_EM_KEY_1;
3283     case EL_EM_KEY2:                    return GFX_EM_KEY_2;
3284     case EL_EM_KEY3:                    return GFX_EM_KEY_3;
3285     case EL_EM_KEY4:                    return GFX_EM_KEY_4;
3286     case EL_PEARL:                      return GFX_PEARL;
3287     case EL_CRYSTAL:                    return GFX_CRYSTAL;
3288     case EL_WALL_PEARL:                 return GFX_WALL_PEARL;
3289     case EL_WALL_CRYSTAL:               return GFX_WALL_CRYSTAL;
3290     case EL_DOOR_WHITE:                 return GFX_DOOR_WHITE;
3291     case EL_DOOR_WHITE_GRAY:            return GFX_DOOR_WHITE_GRAY;
3292     case EL_KEY_WHITE:                  return GFX_KEY_WHITE;
3293     case EL_SHIELD_NORMAL:              return GFX_SHIELD_PASSIVE;
3294     case EL_SHIELD_DEADLY:              return GFX_SHIELD_ACTIVE;
3295     case EL_EXTRA_TIME:                 return GFX_EXTRA_TIME;
3296     case EL_SWITCHGATE_OPEN:            return GFX_SWITCHGATE_OPEN;
3297     case EL_SWITCHGATE_CLOSED:          return GFX_SWITCHGATE_CLOSED;
3298     case EL_SWITCHGATE_SWITCH_UP:       return GFX_SWITCHGATE_SWITCH_1;
3299     case EL_SWITCHGATE_SWITCH_DOWN:     return GFX_SWITCHGATE_SWITCH_2;
3300     case EL_CONVEYOR_BELT1_LEFT:        return GFX_BELT1_LEFT;
3301     case EL_CONVEYOR_BELT1_MIDDLE:      return GFX_BELT1_MIDDLE;
3302     case EL_CONVEYOR_BELT1_RIGHT:       return GFX_BELT1_RIGHT;
3303     case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
3304     case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
3305     case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
3306     case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
3307     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
3308     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
3309     case EL_CONVEYOR_BELT2_LEFT:        return GFX_BELT2_LEFT;
3310     case EL_CONVEYOR_BELT2_MIDDLE:      return GFX_BELT2_MIDDLE;
3311     case EL_CONVEYOR_BELT2_RIGHT:       return GFX_BELT2_RIGHT;
3312     case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
3313     case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
3314     case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
3315     case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
3316     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
3317     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
3318     case EL_CONVEYOR_BELT3_LEFT:        return GFX_BELT3_LEFT;
3319     case EL_CONVEYOR_BELT3_MIDDLE:      return GFX_BELT3_MIDDLE;
3320     case EL_CONVEYOR_BELT3_RIGHT:       return GFX_BELT3_RIGHT;
3321     case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
3322     case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
3323     case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
3324     case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
3325     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
3326     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
3327     case EL_CONVEYOR_BELT4_LEFT:        return GFX_BELT4_LEFT;
3328     case EL_CONVEYOR_BELT4_MIDDLE:      return GFX_BELT4_MIDDLE;
3329     case EL_CONVEYOR_BELT4_RIGHT:       return GFX_BELT4_RIGHT;
3330     case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
3331     case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
3332     case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
3333     case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
3334     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
3335     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
3336     case EL_LANDMINE:                   return GFX_LANDMINE;
3337     case EL_ENVELOPE:                   return GFX_ENVELOPE;
3338     case EL_LIGHT_SWITCH:               return GFX_LIGHT_SWITCH_OFF;
3339     case EL_LIGHT_SWITCH_ACTIVE:        return GFX_LIGHT_SWITCH_ON;
3340     case EL_SIGN_EXCLAMATION:           return GFX_SIGN_EXCLAMATION;
3341     case EL_SIGN_RADIOACTIVITY:         return GFX_SIGN_RADIOACTIVITY;
3342     case EL_SIGN_STOP:                  return GFX_SIGN_STOP;
3343     case EL_SIGN_WHEELCHAIR:            return GFX_SIGN_WHEELCHAIR;
3344     case EL_SIGN_PARKING:               return GFX_SIGN_PARKING;
3345     case EL_SIGN_ONEWAY:                return GFX_SIGN_ONEWAY;
3346     case EL_SIGN_HEART:                 return GFX_SIGN_HEART;
3347     case EL_SIGN_TRIANGLE:              return GFX_SIGN_TRIANGLE;
3348     case EL_SIGN_ROUND:                 return GFX_SIGN_ROUND;
3349     case EL_SIGN_EXIT:                  return GFX_SIGN_EXIT;
3350     case EL_SIGN_YINYANG:               return GFX_SIGN_YINYANG;
3351     case EL_SIGN_OTHER:                 return GFX_SIGN_OTHER;
3352     case EL_MOLE_LEFT:                  return GFX_MOLE_LEFT;
3353     case EL_MOLE_RIGHT:                 return GFX_MOLE_RIGHT;
3354     case EL_MOLE_UP:                    return GFX_MOLE_UP;
3355     case EL_MOLE_DOWN:                  return GFX_MOLE_DOWN;
3356     case EL_STEELWALL_SLANTED:          return GFX_STEEL_SLANTED;
3357     case EL_INVISIBLE_SAND:             return GFX_SAND_INVISIBLE;
3358     case EL_INVISIBLE_SAND_ACTIVE:      return GFX_SAND_INVISIBLE_ON;
3359     case EL_DX_UNKNOWN_15:              return GFX_DX_UNKNOWN_15;
3360     case EL_DX_UNKNOWN_42:              return GFX_DX_UNKNOWN_42;
3361     case EL_TIMEGATE_OPEN:              return GFX_TIMEGATE_OPEN;
3362     case EL_TIMEGATE_CLOSED:            return GFX_TIMEGATE_CLOSED;
3363     case EL_TIMEGATE_SWITCH_ACTIVE:     return GFX_TIMEGATE_SWITCH;
3364     case EL_TIMEGATE_SWITCH:            return GFX_TIMEGATE_SWITCH;
3365     case EL_BALLOON:                    return GFX_BALLOON;
3366     case EL_BALLOON_SEND_LEFT:          return GFX_BALLOON_SEND_LEFT;
3367     case EL_BALLOON_SEND_RIGHT:         return GFX_BALLOON_SEND_RIGHT;
3368     case EL_BALLOON_SEND_UP:            return GFX_BALLOON_SEND_UP;
3369     case EL_BALLOON_SEND_DOWN:          return GFX_BALLOON_SEND_DOWN;
3370     case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
3371     case EL_EMC_STEELWALL1:             return GFX_EMC_STEEL_WALL_1;
3372     case EL_EMC_STEELWALL2:             return GFX_EMC_STEEL_WALL_2;
3373     case EL_EMC_STEELWALL3:             return GFX_EMC_STEEL_WALL_3;
3374     case EL_EMC_STEELWALL4:             return GFX_EMC_STEEL_WALL_4;
3375     case EL_EMC_WALL_PILLAR_UPPER:      return GFX_EMC_WALL_1;
3376     case EL_EMC_WALL_PILLAR_MIDDLE:     return GFX_EMC_WALL_2;
3377     case EL_EMC_WALL_PILLAR_LOWER:      return GFX_EMC_WALL_3;
3378     case EL_EMC_WALL4:                  return GFX_EMC_WALL_4;
3379     case EL_EMC_WALL5:                  return GFX_EMC_WALL_5;
3380     case EL_EMC_WALL6:                  return GFX_EMC_WALL_6;
3381     case EL_EMC_WALL7:                  return GFX_EMC_WALL_7;
3382     case EL_EMC_WALL8:                  return GFX_EMC_WALL_8;
3383     case EL_TUBE_ALL:                   return GFX_TUBE_CROSS;
3384     case EL_TUBE_VERTICAL:              return GFX_TUBE_VERTICAL;
3385     case EL_TUBE_HORIZONTAL:            return GFX_TUBE_HORIZONTAL;
3386     case EL_TUBE_VERTICAL_LEFT:         return GFX_TUBE_VERT_LEFT;
3387     case EL_TUBE_VERTICAL_RIGHT:        return GFX_TUBE_VERT_RIGHT;
3388     case EL_TUBE_HORIZONTAL_UP:         return GFX_TUBE_HORIZ_UP;
3389     case EL_TUBE_HORIZONTAL_DOWN:       return GFX_TUBE_HORIZ_DOWN;
3390     case EL_TUBE_LEFT_UP:               return GFX_TUBE_LEFT_UP;
3391     case EL_TUBE_LEFT_DOWN:             return GFX_TUBE_LEFT_DOWN;
3392     case EL_TUBE_RIGHT_UP:              return GFX_TUBE_RIGHT_UP;
3393     case EL_TUBE_RIGHT_DOWN:            return GFX_TUBE_RIGHT_DOWN;
3394     case EL_SPRING:                     return GFX_SPRING;
3395     case EL_SPRING_MOVING:              return GFX_SPRING;
3396     case EL_TRAP:                       return GFX_TRAP_INACTIVE;
3397     case EL_TRAP_ACTIVE:                return GFX_TRAP_ACTIVE;
3398     case EL_BD_WALL:                    return GFX_BD_WALL;
3399     case EL_BD_ROCK:                    return GFX_BD_ROCK;
3400     case EL_DX_SUPABOMB:                return GFX_DX_SUPABOMB;
3401     case EL_SP_MURPHY_CLONE:            return GFX_SP_MURPHY_CLONE;
3402
3403     default:
3404     {
3405       if (IS_CHAR(element))
3406         return GFX_CHAR_START + (element - EL_CHAR_START);
3407       else if (element >= EL_SP_START && element <= EL_SP_END)
3408       {
3409         int nr_element = element - EL_SP_START;
3410         int gfx_per_line = 8;
3411         int nr_graphic =
3412           (nr_element / gfx_per_line) * SP_PER_LINE +
3413           (nr_element % gfx_per_line);
3414
3415         return GFX_START_ROCKSSP + nr_graphic;
3416       }
3417       else
3418         return -1;
3419     }
3420   }
3421 }
3422
3423 int el2gfx(int element)
3424 {
3425 #if 1
3426   int graphic_OLD = el2gfx_OLD(element);
3427
3428   return graphic_OLD;
3429 #else
3430
3431   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
3432
3433 #if DEBUG
3434   int graphic_OLD = el2gfx_OLD(element);
3435
3436   if (element >= MAX_ELEMENTS)
3437   {
3438     Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
3439   }
3440
3441   if (graphic_NEW != graphic_OLD)
3442   {
3443     Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
3444           graphic_NEW, graphic_OLD);
3445   }
3446 #endif
3447
3448   return graphic_NEW;
3449 #endif
3450 }
3451
3452 int el2img(int element)
3453 {
3454 #if 1
3455   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
3456
3457 #if DEBUG
3458   if (graphic_NEW < 0)
3459     Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
3460           element, graphic_NEW);
3461 #endif
3462
3463   return graphic_NEW;
3464 #else
3465
3466   switch(element)
3467   {
3468     case EL_BD_BUTTERFLY:       return IMG_BD_BUTTERFLY;
3469     case EL_BD_FIREFLY:         return IMG_BD_FIREFLY;
3470     case EL_SP_ELECTRON:        return IMG_SP_ELECTRON;
3471
3472     default:
3473       break;
3474   }
3475
3476   return IMG_EMPTY;
3477 #endif
3478 }
3479
3480 int el_dir2img(int element, int direction)
3481 {
3482   return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
3483 }
3484
3485 int el_dir_act2img(int element, int direction, int action)
3486 {
3487   action = graphics_action_mapping[action];
3488   direction = MV_DIR_BIT(direction);
3489
3490   return element_info[element].direction_graphic[action][direction];
3491 }