rnd-20021024-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES        0
25 #define TOOL_CTRL_ID_NO         1
26 #define TOOL_CTRL_ID_CONFIRM    2
27 #define TOOL_CTRL_ID_PLAYER_1   3
28 #define TOOL_CTRL_ID_PLAYER_2   4
29 #define TOOL_CTRL_ID_PLAYER_3   5
30 #define TOOL_CTRL_ID_PLAYER_4   6
31
32 #define NUM_TOOL_BUTTONS        7
33
34 /* forward declaration for internal use */
35 static int getGraphicAnimationPhase(int, int, int);
36 static void UnmapToolButtons();
37 static void HandleToolButtons(struct GadgetInfo *);
38
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
41
42 void SetDrawtoField(int mode)
43 {
44   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
45   {
46     FX = TILEX;
47     FY = TILEY;
48     BX1 = -1;
49     BY1 = -1;
50     BX2 = SCR_FIELDX;
51     BY2 = SCR_FIELDY;
52     redraw_x1 = 1;
53     redraw_y1 = 1;
54
55     drawto_field = fieldbuffer;
56   }
57   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
58   {
59     FX = SX;
60     FY = SY;
61     BX1 = 0;
62     BY1 = 0;
63     BX2 = SCR_FIELDX - 1;
64     BY2 = SCR_FIELDY - 1;
65     redraw_x1 = 0;
66     redraw_y1 = 0;
67
68     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
69   }
70 }
71
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 {
74   if (game_status == PLAYING)
75   {
76     if (force_redraw)
77     {
78       x = gfx.sx - TILEX;
79       y = gfx.sy - TILEY;
80       width = gfx.sxsize + 2 * TILEX;
81       height = gfx.sysize + 2 * TILEY;
82     }
83
84     if (force_redraw || setup.direct_draw)
85     {
86       int xx, yy;
87       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89
90       if (setup.direct_draw)
91         SetDrawtoField(DRAW_BACKBUFFER);
92
93       for(xx=BX1; xx<=BX2; xx++)
94         for(yy=BY1; yy<=BY2; yy++)
95           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96             DrawNewScreenField(xx, yy);
97       DrawAllPlayers();
98
99       if (setup.direct_draw)
100         SetDrawtoField(DRAW_DIRECT);
101     }
102
103     if (setup.soft_scrolling)
104     {
105       int fx = FX, fy = FY;
106
107       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
109
110       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
111     }
112   }
113
114   BlitBitmap(drawto, window, x, y, width, height, x, y);
115 }
116
117 void BackToFront()
118 {
119   int x,y;
120   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121
122   if (setup.direct_draw && game_status == PLAYING)
123     redraw_mask &= ~REDRAW_MAIN;
124
125   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126     redraw_mask |= REDRAW_FIELD;
127
128   if (redraw_mask & REDRAW_FIELD)
129     redraw_mask &= ~REDRAW_TILES;
130
131   if (redraw_mask == REDRAW_NONE)
132     return;
133
134   if (global.fps_slowdown && game_status == PLAYING)
135   {
136     static boolean last_frame_skipped = FALSE;
137     boolean skip_even_when_not_scrolling = TRUE;
138     boolean just_scrolling = (ScreenMovDir != 0);
139     boolean verbose = FALSE;
140
141     if (global.fps_slowdown_factor > 1 &&
142         (FrameCounter % global.fps_slowdown_factor) &&
143         (just_scrolling || skip_even_when_not_scrolling))
144     {
145       redraw_mask &= ~REDRAW_MAIN;
146
147       last_frame_skipped = TRUE;
148
149       if (verbose)
150         printf("FRAME SKIPPED\n");
151     }
152     else
153     {
154       if (last_frame_skipped)
155         redraw_mask |= REDRAW_FIELD;
156
157       last_frame_skipped = FALSE;
158
159       if (verbose)
160         printf("frame not skipped\n");
161     }
162   }
163
164   /* synchronize X11 graphics at this point; if we would synchronize the
165      display immediately after the buffer switching (after the XFlush),
166      this could mean that we have to wait for the graphics to complete,
167      although we could go on doing calculations for the next frame */
168
169   SyncDisplay();
170
171   if (redraw_mask & REDRAW_ALL)
172   {
173     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
174     redraw_mask = 0;
175   }
176
177   if (redraw_mask & REDRAW_FIELD)
178   {
179     if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180     {
181       BlitBitmap(backbuffer, window,
182                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
183     }
184     else
185     {
186       int fx = FX, fy = FY;
187
188       if (setup.soft_scrolling)
189       {
190         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
192       }
193
194       if (setup.soft_scrolling ||
195           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196           ABS(ScreenMovPos) == ScrollStepSize ||
197           redraw_tiles > REDRAWTILES_THRESHOLD)
198       {
199         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
200
201 #ifdef DEBUG
202 #if 0
203         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204                ScreenGfxPos,
205                (setup.soft_scrolling ?
206                 "setup.soft_scrolling" :
207                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209                 ABS(ScreenGfxPos) == ScrollStepSize ?
210                 "ABS(ScreenGfxPos) == ScrollStepSize" :
211                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
212 #endif
213 #endif
214       }
215     }
216
217     redraw_mask &= ~REDRAW_MAIN;
218   }
219
220   if (redraw_mask & REDRAW_DOORS)
221   {
222     if (redraw_mask & REDRAW_DOOR_1)
223       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224     if (redraw_mask & REDRAW_DOOR_2)
225     {
226       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227         BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
228       else
229       {
230         if (redraw_mask & REDRAW_VIDEO_1)
231           BlitBitmap(backbuffer, window,
232                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235         if (redraw_mask & REDRAW_VIDEO_2)
236           BlitBitmap(backbuffer, window,
237                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240         if (redraw_mask & REDRAW_VIDEO_3)
241           BlitBitmap(backbuffer, window,
242                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243                      VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
245       }
246     }
247     if (redraw_mask & REDRAW_DOOR_3)
248       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
249     redraw_mask &= ~REDRAW_DOORS;
250   }
251
252   if (redraw_mask & REDRAW_MICROLEVEL)
253   {
254     BlitBitmap(backbuffer, window,
255                MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
256                MICROLEV_XPOS, MICROLEV_YPOS);
257     BlitBitmap(backbuffer, window,
258                SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
259                SX, MICROLABEL_YPOS);
260     redraw_mask &= ~REDRAW_MICROLEVEL;
261   }
262
263   if (redraw_mask & REDRAW_TILES)
264   {
265     for(x=0; x<SCR_FIELDX; x++)
266       for(y=0; y<SCR_FIELDY; y++)
267         if (redraw[redraw_x1 + x][redraw_y1 + y])
268           BlitBitmap(buffer, window,
269                      FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270                      SX + x * TILEX, SY + y * TILEY);
271   }
272
273   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
274   {
275     char text[100];
276     char info1[100];
277
278     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279     if (!global.fps_slowdown)
280       info1[0] = '\0';
281
282     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283     DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW);
284   }
285
286   FlushDisplay();
287
288   for(x=0; x<MAX_BUF_XSIZE; x++)
289     for(y=0; y<MAX_BUF_YSIZE; y++)
290       redraw[x][y] = 0;
291   redraw_tiles = 0;
292   redraw_mask = REDRAW_NONE;
293 }
294
295 void FadeToFront()
296 {
297 #if 0
298   long fading_delay = 300;
299
300   if (setup.fading && (redraw_mask & REDRAW_FIELD))
301   {
302 #endif
303
304 #if 0
305     int x,y;
306
307     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
308     FlushDisplay();
309
310     for(i=0;i<2*FULL_SYSIZE;i++)
311     {
312       for(y=0;y<FULL_SYSIZE;y++)
313       {
314         BlitBitmap(backbuffer, window,
315                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
316       }
317       FlushDisplay();
318       Delay(10);
319     }
320 #endif
321
322 #if 0
323     for(i=1;i<FULL_SYSIZE;i+=2)
324       BlitBitmap(backbuffer, window,
325                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
326     FlushDisplay();
327     Delay(fading_delay);
328 #endif
329
330 #if 0
331     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332     BlitBitmapMasked(backbuffer, window,
333                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
334                      REAL_SX,REAL_SY);
335     FlushDisplay();
336     Delay(fading_delay);
337
338     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339     BlitBitmapMasked(backbuffer, window,
340                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
341                      REAL_SX,REAL_SY);
342     FlushDisplay();
343     Delay(fading_delay);
344
345     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346     BlitBitmapMasked(backbuffer, window,
347                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
348                      REAL_SX,REAL_SY);
349     FlushDisplay();
350     Delay(fading_delay);
351
352     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353     BlitBitmapMasked(backbuffer, window,
354                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
355                      REAL_SX,REAL_SY);
356     FlushDisplay();
357     Delay(fading_delay);
358
359     redraw_mask &= ~REDRAW_MAIN;
360   }
361 #endif
362
363   BackToFront();
364 }
365
366 void ClearWindow()
367 {
368   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
369
370   if (setup.soft_scrolling && game_status == PLAYING)
371   {
372     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
373     SetDrawtoField(DRAW_BUFFERED);
374   }
375   else
376     SetDrawtoField(DRAW_BACKBUFFER);
377
378   if (setup.direct_draw && game_status == PLAYING)
379   {
380     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
381     SetDrawtoField(DRAW_DIRECT);
382   }
383
384   redraw_mask |= REDRAW_FIELD;
385 }
386
387 void MarkTileDirty(int x, int y)
388 {
389   int xx = redraw_x1 + x;
390   int yy = redraw_y1 + y;
391
392   if (!redraw[xx][yy])
393     redraw_tiles++;
394
395   redraw[xx][yy] = TRUE;
396   redraw_mask |= REDRAW_TILES;
397 }
398
399 void SetBorderElement()
400 {
401   int x, y;
402
403   BorderElement = EL_EMPTY;
404
405   for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
406   {
407     for(x=0; x<lev_fieldx; x++)
408     {
409       if (!IS_MASSIVE(Feld[x][y]))
410         BorderElement = EL_STEELWALL;
411
412       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
413         x = lev_fieldx - 2;
414     }
415   }
416 }
417
418 void DrawAllPlayers()
419 {
420   int i;
421
422   for(i=0; i<MAX_PLAYERS; i++)
423     if (stored_player[i].active)
424       DrawPlayer(&stored_player[i]);
425 }
426
427 void DrawPlayerField(int x, int y)
428 {
429   if (!IS_PLAYER(x, y))
430     return;
431
432   DrawPlayer(PLAYERINFO(x, y));
433 }
434
435 void DrawPlayer(struct PlayerInfo *player)
436 {
437   int jx = player->jx, jy = player->jy;
438   int last_jx = player->last_jx, last_jy = player->last_jy;
439   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
440   int sx = SCREENX(jx), sy = SCREENY(jy);
441   int sxx = 0, syy = 0;
442   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
443   int graphic;
444   int frame = 0;
445   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
446
447   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
448     return;
449
450 #if DEBUG
451   if (!IN_LEV_FIELD(jx,jy))
452   {
453     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
454     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
455     printf("DrawPlayerField(): This should never happen!\n");
456     return;
457   }
458 #endif
459
460   if (element == EL_EXPLOSION)
461     return;
462
463   /* draw things in the field the player is leaving, if needed */
464
465   if (player_is_moving)
466   {
467     if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
468     {
469       DrawNewLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
470
471       if (last_element == EL_DYNAMITE_ACTIVE)
472         DrawDynamite(last_jx, last_jy);
473       else
474         DrawNewLevelFieldThruMask(last_jx, last_jy);
475     }
476     else if (last_element == EL_DYNAMITE_ACTIVE)
477       DrawDynamite(last_jx, last_jy);
478     else
479       DrawNewLevelField(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           DrawNewLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
487         else
488           DrawNewLevelElement(next_jx, next_jy, EL_EMPTY);
489       }
490       else
491         DrawNewLevelField(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     DrawNewLevelElement(jx, jy, Store[jx][jy]);
505   else if (!IS_ACTIVE_BOMB(element))
506     DrawNewLevelField(jx, jy);
507   else
508     DrawNewLevelElement(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 = IMG_SP_MURPHY;
523
524     if (player->Pushing)
525     {
526       if (player->MovDir == MV_LEFT)
527         graphic = IMG_SP_MURPHY_LEFT_PUSHING;
528       else if (player->MovDir == MV_RIGHT)
529         graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
530       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
531         graphic = IMG_SP_MURPHY_LEFT_PUSHING;
532       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
533         graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
534     }
535     else if (player->snapped)
536     {
537       if (player->MovDir == MV_LEFT)
538         graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
539       else if (player->MovDir == MV_RIGHT)
540         graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
541       else if (player->MovDir == MV_UP)
542         graphic = IMG_SP_MURPHY_UP_SNAPPING;
543       else if (player->MovDir == MV_DOWN)
544         graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
545     }
546     else if (action_moving)
547     {
548       if (player->MovDir == MV_LEFT)
549         graphic = IMG_SP_MURPHY_LEFT_MOVING;
550       else if (player->MovDir == MV_RIGHT)
551         graphic = IMG_SP_MURPHY_RIGHT_MOVING;
552       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
553         graphic = IMG_SP_MURPHY_LEFT_MOVING;
554       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
555         graphic = IMG_SP_MURPHY_RIGHT_MOVING;
556       else
557         graphic = IMG_SP_MURPHY_LEFT_MOVING;
558
559       frame = getNewGraphicAnimationFrame(graphic, -1);
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 = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
569                  IMG_PLAYER1_LEFT_MOVING);
570     else if (player->MovDir == MV_RIGHT)
571       graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
572                  IMG_PLAYER1_RIGHT_MOVING);
573     else if (player->MovDir == MV_UP)
574       graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
575                  IMG_PLAYER1_UP_MOVING);
576     else        /* MV_DOWN || MV_NO_MOVING */
577       graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
578                  IMG_PLAYER1_DOWN_MOVING);
579
580     graphic = PLAYER_NR_GFX(graphic, player->index_nr);
581
582     frame = player->Frame;
583   }
584
585   if (player->GfxPos)
586   {
587     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
588       sxx = player->GfxPos;
589     else
590       syy = player->GfxPos;
591   }
592
593   if (!setup.soft_scrolling && ScreenMovPos)
594     sxx = syy = 0;
595
596   DrawNewGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
597
598   if (SHIELD_ON(player))
599   {
600     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
601                    IMG_SHIELD_NORMAL_ACTIVE);
602     int frame = getNewGraphicAnimationFrame(graphic, -1);
603
604     DrawNewGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
605   }
606
607   if (player->Pushing && player->GfxPos)
608   {
609     int px = SCREENX(next_jx), py = SCREENY(next_jy);
610
611     if (element == EL_SOKOBAN_FIELD_EMPTY ||
612         Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
613       DrawNewGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT, 0,
614                                  NO_CUTTING);
615     else
616     {
617       int element = Feld[next_jx][next_jy];
618       int graphic = el2img(element);
619       int frame = 0;
620
621       if ((element == EL_ROCK ||
622            element == EL_SP_ZONK ||
623            element == EL_BD_ROCK) && sxx)
624       {
625         graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_PUSHING);
626         frame = getNewGraphicAnimationFrame(graphic, player->GfxPos);
627
628         /* !!! FIX !!! */
629         if (player->MovDir == MV_LEFT)
630           frame = 3 - frame;
631
632 #if 0
633         frame = (player->GfxPos / (TILEX / 4));
634
635         if (player->MovDir == MV_RIGHT)
636           frame = (frame + 4) % 4;
637 #endif
638       }
639
640       DrawNewGraphicShifted(px, py, sxx, syy, graphic, frame,
641                             NO_CUTTING, NO_MASKING);
642     }
643   }
644
645   /* draw things in front of player (active dynamite or dynabombs) */
646
647   if (IS_ACTIVE_BOMB(element))
648   {
649     graphic = el2img(element);
650
651 #if 0
652     if (element == EL_DYNAMITE_ACTIVE)
653     {
654       if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
655         frame = 6;
656     }
657     else
658     {
659       if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
660         frame = 7 - frame;
661     }
662 #else
663     frame = getNewGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
664 #endif
665
666     if (game.emulation == EMU_SUPAPLEX)
667       DrawNewGraphic(sx, sy, GFX_SP_DISK_RED, 0);
668     else
669       DrawNewGraphicThruMask(sx, sy, graphic, frame);
670   }
671
672   if (player_is_moving && last_element == EL_EXPLOSION)
673   {
674     int frame = Frame[last_jx][last_jy];
675     int delay = 2;
676
677     if (frame > 2)
678       DrawNewGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy),
679                              GFX_EXPLOSION, ((frame - 1) / delay - 1));
680   }
681
682   /* draw elements that stay over the player */
683   /* handle the field the player is leaving ... */
684   if (player_is_moving && IS_OVER_PLAYER(last_element))
685     DrawNewLevelField(last_jx, last_jy);
686   /* ... and the field the player is entering */
687   if (IS_OVER_PLAYER(element))
688     DrawNewLevelField(jx, jy);
689
690   if (setup.direct_draw)
691   {
692     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
693     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
694     int x_size = TILEX * (1 + ABS(jx - last_jx));
695     int y_size = TILEY * (1 + ABS(jy - last_jy));
696
697     BlitBitmap(drawto_field, window,
698                dest_x, dest_y, x_size, y_size, dest_x, dest_y);
699     SetDrawtoField(DRAW_DIRECT);
700   }
701
702   MarkTileDirty(sx,sy);
703 }
704
705 static int getGraphicAnimationPhase(int frames, int delay, int mode)
706 {
707   int phase;
708
709   if (mode & ANIM_PINGPONG)
710   {
711     int max_anim_frames = 2 * frames - 2;
712
713     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
714     phase = (phase < frames ? phase : max_anim_frames - phase);
715   }
716   else
717     phase = (FrameCounter % (delay * frames)) / delay;
718
719   if (mode & ANIM_REVERSE)
720     phase = -phase;
721
722   return phase;
723 }
724
725 int getNewGraphicAnimationFrame(int graphic, int sync_frame)
726 {
727   int num_frames = new_graphic_info[graphic].anim_frames;
728   int delay = new_graphic_info[graphic].anim_delay;
729   int mode = new_graphic_info[graphic].anim_mode;
730   int frame = 0;
731
732   /* animation synchronized with global frame counter, not move position */
733   if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
734     sync_frame = FrameCounter;
735
736   if (mode & ANIM_LOOP)                 /* normal, looping animation */
737   {
738     frame = (sync_frame % (delay * num_frames)) / delay;
739   }
740   else if (mode & ANIM_LINEAR)          /* normal, non-looping animation */
741   {
742     frame = sync_frame / delay;
743
744     if (frame > num_frames - 1)
745       frame = num_frames - 1;
746   }
747   else if (mode & ANIM_PINGPONG)        /* use border frames once */
748   {
749     int max_anim_frames = 2 * num_frames - 2;
750
751     frame = (sync_frame % (delay * max_anim_frames)) / delay;
752     frame = (frame < num_frames ? frame : max_anim_frames - frame);
753   }
754   else if (mode & ANIM_PINGPONG2)       /* use border frames twice */
755   {
756     int max_anim_frames = 2 * num_frames;
757
758     frame = (sync_frame % (delay * max_anim_frames)) / delay;
759     frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
760   }
761
762   if (mode & ANIM_REVERSE)              /* use reverse animation direction */
763     frame = num_frames - frame - 1;
764
765   return frame;
766 }
767
768 void DrawNewGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
769 {
770 #if 0
771   int delay = new_graphic_info[graphic].anim_delay;
772
773   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
774 #else
775   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
776 #endif
777   {
778     int frame = getNewGraphicAnimationFrame(graphic, -1);
779
780     if (mask_mode == USE_MASKING)
781       DrawNewGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
782     else
783       DrawNewGraphic(SCREENX(x), SCREENY(y), graphic, frame);
784   }
785 }
786
787 #if 0
788 void DrawOldGraphicAnimation(int x, int y, int graphic,
789                              int frames, int delay, int mode)
790 {
791   DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
792 }
793 #endif
794
795 void DrawNewGraphicAnimation(int x, int y, int graphic)
796 {
797   DrawNewGraphicAnimationExt(x, y, graphic, NO_MASKING);
798 }
799
800 #if 1
801 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
802 {
803   if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
804   {
805     *bitmap = graphic_info[graphic].bitmap;
806     *x = graphic_info[graphic].src_x;
807     *y = graphic_info[graphic].src_y;
808   }
809   else if (graphic >= GFX_START_ROCKSELEMENTS &&
810            graphic <= GFX_END_ROCKSELEMENTS)
811   {
812     graphic -= GFX_START_ROCKSELEMENTS;
813     *bitmap = pix[PIX_ELEMENTS];
814     *x = (graphic % GFX_PER_LINE) * TILEX;
815     *y = (graphic / GFX_PER_LINE) * TILEY;
816   }
817   else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
818   {
819     graphic -= GFX_START_ROCKSHEROES;
820     *bitmap = pix[PIX_HEROES];
821     *x = (graphic % HEROES_PER_LINE) * TILEX;
822     *y = (graphic / HEROES_PER_LINE) * TILEY;
823   }
824   else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
825   {
826     graphic -= GFX_START_ROCKSSP;
827     *bitmap = pix[PIX_SP];
828     *x = (graphic % SP_PER_LINE) * TILEX;
829     *y = (graphic / SP_PER_LINE) * TILEY;
830   }
831   else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
832   {
833     graphic -= GFX_START_ROCKSDC;
834     *bitmap = pix[PIX_DC];
835     *x = (graphic % DC_PER_LINE) * TILEX;
836     *y = (graphic / DC_PER_LINE) * TILEY;
837   }
838   else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
839   {
840     graphic -= GFX_START_ROCKSMORE;
841     *bitmap = pix[PIX_MORE];
842     *x = (graphic % MORE_PER_LINE) * TILEX;
843     *y = (graphic / MORE_PER_LINE) * TILEY;
844   }
845   else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
846   {
847     graphic -= GFX_START_ROCKSFONT;
848     *bitmap = pix[PIX_FONT_EM];
849     *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
850     *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
851   }
852   else
853   {
854     *bitmap = pix[PIX_SP];
855     *x = 0;
856     *y = 0;
857   }
858 }
859 #endif
860
861 void DrawNewGraphic(int x, int y, int graphic, int frame)
862 {
863 #if DEBUG
864   if (!IN_SCR_FIELD(x, y))
865   {
866     printf("DrawNewGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
867     printf("DrawNewGraphic(): This should never happen!\n");
868     return;
869   }
870 #endif
871
872   DrawNewGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
873                     graphic, frame);
874   MarkTileDirty(x, y);
875 }
876
877 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
878 {
879   Bitmap *src_bitmap;
880   int src_x, src_y;
881
882   getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
883   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
884 }
885
886 void DrawNewGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
887                        int frame)
888 {
889   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
890   int src_x = new_graphic_info[graphic].src_x;
891   int src_y = new_graphic_info[graphic].src_y;
892   int offset_x = new_graphic_info[graphic].offset_x;
893   int offset_y = new_graphic_info[graphic].offset_y;
894
895   src_x += frame * offset_x;
896   src_y += frame * offset_y;
897
898   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
899 }
900
901 void DrawNewGraphicThruMask(int x, int y, int graphic, int frame)
902 {
903 #if DEBUG
904   if (!IN_SCR_FIELD(x, y))
905   {
906     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
907     printf("DrawGraphicThruMask(): This should never happen!\n");
908     return;
909   }
910 #endif
911
912   DrawNewGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY,
913                             graphic, frame);
914   MarkTileDirty(x, y);
915 }
916
917 void DrawNewGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y,
918                                int graphic, int frame)
919 {
920   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
921   GC drawing_gc = src_bitmap->stored_clip_gc;
922   int src_x = new_graphic_info[graphic].src_x;
923   int src_y = new_graphic_info[graphic].src_y;
924   int offset_x = new_graphic_info[graphic].offset_x;
925   int offset_y = new_graphic_info[graphic].offset_y;
926
927   src_x += frame * offset_x;
928   src_y += frame * offset_y;
929
930   SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
931   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
932 }
933
934 void DrawNewMiniGraphic(int x, int y, int graphic)
935 {
936   DrawNewMiniGraphicExt(drawto,
937                         SX + x * MINI_TILEX, SY + y * MINI_TILEY, graphic);
938   MarkTileDirty(x / 2, y / 2);
939 }
940
941 void getNewMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
942 {
943   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
944   int mini_startx = 0;
945   int mini_starty = src_bitmap->height * 2 / 3;
946   int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
947   int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
948
949   *bitmap = src_bitmap;
950   *x = src_x;
951   *y = src_y;
952 }
953
954 void DrawNewMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
955 {
956   Bitmap *src_bitmap;
957   int src_x, src_y;
958
959   getNewMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
960   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
961 }
962
963 void DrawNewGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
964                         int cut_mode, int mask_mode)
965 {
966   Bitmap *src_bitmap;
967   GC drawing_gc;
968   int src_x;
969   int src_y;
970   int offset_x;
971   int offset_y;
972
973   int width = TILEX, height = TILEY;
974   int cx = 0, cy = 0;
975   int dest_x, dest_y;
976
977   if (graphic < 0)
978   {
979     DrawNewGraphic(x, y, graphic, frame);
980     return;
981   }
982
983   if (dx || dy)                 /* shifted graphic */
984   {
985     if (x < BX1)                /* object enters playfield from the left */
986     {
987       x = BX1;
988       width = dx;
989       cx = TILEX - dx;
990       dx = 0;
991     }
992     else if (x > BX2)           /* object enters playfield from the right */
993     {
994       x = BX2;
995       width = -dx;
996       dx = TILEX + dx;
997     }
998     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
999     {
1000       width += dx;
1001       cx = -dx;
1002       dx = 0;
1003     }
1004     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1005       width -= dx;
1006     else if (dx)                /* general horizontal movement */
1007       MarkTileDirty(x + SIGN(dx), y);
1008
1009     if (y < BY1)                /* object enters playfield from the top */
1010     {
1011       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1012         return;
1013
1014       y = BY1;
1015       height = dy;
1016       cy = TILEY - dy;
1017       dy = 0;
1018     }
1019     else if (y > BY2)           /* object enters playfield from the bottom */
1020     {
1021       y = BY2;
1022       height = -dy;
1023       dy = TILEY + dy;
1024     }
1025     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1026     {
1027       height += dy;
1028       cy = -dy;
1029       dy = 0;
1030     }
1031     else if (dy > 0 && cut_mode == CUT_ABOVE)
1032     {
1033       if (y == BY2)             /* object completely above bottom border */
1034         return;
1035
1036       height = dy;
1037       cy = TILEY - dy;
1038       dy = TILEY;
1039       MarkTileDirty(x, y + 1);
1040     }                           /* object leaves playfield to the bottom */
1041     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1042       height -= dy;
1043     else if (dy)                /* general vertical movement */
1044       MarkTileDirty(x, y + SIGN(dy));
1045   }
1046
1047   src_bitmap = new_graphic_info[graphic].bitmap;
1048   src_x = new_graphic_info[graphic].src_x;
1049   src_y = new_graphic_info[graphic].src_y;
1050   offset_x = new_graphic_info[graphic].offset_x;
1051   offset_y = new_graphic_info[graphic].offset_y;
1052
1053   drawing_gc = src_bitmap->stored_clip_gc;
1054
1055   src_x += frame * offset_x;
1056   src_y += frame * offset_y;
1057
1058   src_x += cx;
1059   src_y += cy;
1060
1061   dest_x = FX + x * TILEX + dx;
1062   dest_y = FY + y * TILEY + dy;
1063
1064 #if DEBUG
1065   if (!IN_SCR_FIELD(x,y))
1066   {
1067     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1068     printf("DrawGraphicShifted(): This should never happen!\n");
1069     return;
1070   }
1071 #endif
1072
1073   if (mask_mode == USE_MASKING)
1074   {
1075     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1076     BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1077                      dest_x, dest_y);
1078   }
1079   else
1080     BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1081                dest_x, dest_y);
1082
1083   MarkTileDirty(x,y);
1084 }
1085
1086 void DrawNewGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1087                                    int frame, int cut_mode)
1088 {
1089   DrawNewGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1090 }
1091
1092 #if 0
1093 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1094                           int cut_mode, int mask_mode)
1095 {
1096   int ux = LEVELX(x), uy = LEVELY(y);
1097   int graphic = el2gfx(element);
1098   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1099   int phase4 = phase8 / 2;
1100   int phase2  = phase8 / 4;
1101   int dir = MovDir[ux][uy];
1102
1103   if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1104   {
1105     graphic += 1 * !phase2;
1106
1107     if (dir == MV_UP)
1108       graphic += 1 * 2;
1109     else if (dir == MV_LEFT)
1110       graphic += 2 * 2;
1111     else if (dir == MV_DOWN)
1112       graphic += 3 * 2;
1113   }
1114   else if (element == EL_SP_SNIKSNAK)
1115   {
1116     if (dir == MV_LEFT)
1117       graphic = GFX_SP_SNIKSNAK_LEFT;
1118     else if (dir == MV_RIGHT)
1119       graphic = GFX_SP_SNIKSNAK_RIGHT;
1120     else if (dir == MV_UP)
1121       graphic = GFX_SP_SNIKSNAK_UP;
1122     else
1123       graphic = GFX_SP_SNIKSNAK_DOWN;
1124
1125     graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1126   }
1127   else if (element == EL_SP_ELECTRON)
1128   {
1129     graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1130   }
1131   else if (element == EL_MOLE || element == EL_PENGUIN ||
1132            element == EL_PIG || element == EL_DRAGON)
1133   {
1134     if (dir == MV_LEFT)
1135       graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1136                  element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1137                  element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1138     else if (dir == MV_RIGHT)
1139       graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1140                  element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1141                  element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1142     else if (dir == MV_UP)
1143       graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1144                  element == EL_PENGUIN ? GFX_PINGUIN_UP :
1145                  element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1146     else
1147       graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1148                  element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1149                  element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1150
1151     graphic += phase4;
1152   }
1153   else if (element == EL_SATELLITE)
1154   {
1155     graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1156   }
1157   else if (element == EL_ACID)
1158   {
1159     graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1160   }
1161   else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1162   {
1163     graphic += !phase2;
1164   }
1165   else if (element == EL_BALLOON)
1166   {
1167     graphic += phase4;
1168   }
1169   else if ((element == EL_ROCK ||
1170             element == EL_SP_ZONK ||
1171             element == EL_BD_ROCK ||
1172             element == EL_SP_INFOTRON ||
1173             IS_GEM(element))
1174            && !cut_mode)
1175   {
1176     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1177     {
1178       if (element == EL_ROCK ||
1179           element == EL_SP_ZONK ||
1180           element == EL_BD_ROCK)
1181       {
1182         if (dir == MV_LEFT)
1183           graphic += (4 - phase4) % 4;
1184         else if (dir == MV_RIGHT)
1185           graphic += phase4;
1186         else
1187           graphic += phase2 * 2;
1188       }
1189       else if (element != EL_SP_INFOTRON)
1190         graphic += phase2;
1191     }
1192   }
1193   else if (element == EL_MAGIC_WALL_ACTIVE ||
1194            element == EL_MAGIC_WALL_EMPTYING ||
1195            element == EL_BD_MAGIC_WALL_ACTIVE ||
1196            element == EL_BD_MAGIC_WALL_EMPTYING ||
1197            element == EL_MAGIC_WALL_FULL ||
1198            element == EL_BD_MAGIC_WALL_FULL)
1199   {
1200     graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1201   }
1202   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1203   {
1204     graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1205     graphic += (x + 2 * y + 4) % 4;
1206   }
1207   else if (element == EL_WALL_GROWING)
1208   {
1209     boolean links_massiv = FALSE, rechts_massiv = FALSE;
1210
1211     if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1212       links_massiv = TRUE;
1213     if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1214       rechts_massiv = TRUE;
1215
1216     if (links_massiv && rechts_massiv)
1217       graphic = GFX_MAUERWERK;
1218     else if (links_massiv)
1219       graphic = GFX_MAUER_R;
1220     else if (rechts_massiv)
1221       graphic = GFX_MAUER_L;
1222   }
1223 #if 0
1224   else if ((element == EL_INVISIBLE_STEELWALL ||
1225             element == EL_INVISIBLE_WALL ||
1226             element == EL_INVISIBLE_SAND) && game.light_time_left)
1227   {
1228     graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1229                element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1230                GFX_SAND_INVISIBLE_ON);
1231   }
1232 #endif
1233
1234   if (dx || dy)
1235     DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1236   else if (mask_mode == USE_MASKING)
1237     DrawGraphicThruMask(x, y, graphic);
1238   else
1239     DrawGraphic(x, y, graphic);
1240 }
1241 #endif
1242
1243 inline static int getFramePosition(int x, int y)
1244 {
1245   int element = Feld[x][y];
1246   int frame_pos = -1;
1247
1248   if (element == EL_QUICKSAND_FULL ||
1249       element == EL_MAGIC_WALL_FULL ||
1250       element == EL_BD_MAGIC_WALL_FULL)
1251     frame_pos = -1;
1252   else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1253     frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1254
1255   return frame_pos;
1256 }
1257
1258 inline static int getGfxAction(int x, int y)
1259 {
1260   int gfx_action = GFX_ACTION_DEFAULT;
1261
1262   if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1263     gfx_action = GfxAction[x][y];
1264   else if (IS_MOVING(x, y))
1265     gfx_action = GFX_ACTION_MOVING;
1266
1267   return gfx_action;
1268 }
1269
1270 void DrawNewScreenElementExt(int x, int y, int dx, int dy, int element,
1271                              int cut_mode, int mask_mode)
1272 {
1273   int ux = LEVELX(x), uy = LEVELY(y);
1274   int move_dir = MovDir[ux][uy];
1275   int move_pos = getFramePosition(ux, uy);
1276   int gfx_action = getGfxAction(ux, uy);
1277   int graphic = el_dir_act2img(element, move_dir, gfx_action);
1278   int frame = getNewGraphicAnimationFrame(graphic, move_pos);
1279
1280   if (element == EL_WALL_GROWING)
1281   {
1282     boolean left_stopped = FALSE, right_stopped = FALSE;
1283
1284     if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1285       left_stopped = TRUE;
1286     if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1287       right_stopped = TRUE;
1288
1289     if (left_stopped && right_stopped)
1290       graphic = IMG_WALL;
1291     else if (left_stopped)
1292     {
1293       graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1294       frame = new_graphic_info[graphic].anim_frames - 1;
1295     }
1296     else if (right_stopped)
1297     {
1298       graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1299       frame = new_graphic_info[graphic].anim_frames - 1;
1300     }
1301   }
1302 #if 0
1303   else if ((element == EL_ROCK ||
1304             element == EL_SP_ZONK ||
1305             element == EL_BD_ROCK ||
1306             element == EL_SP_INFOTRON ||
1307             IS_GEM(element))
1308            && !cut_mode)
1309   {
1310     if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1311     {
1312       if (element == EL_ROCK ||
1313           element == EL_SP_ZONK ||
1314           element == EL_BD_ROCK)
1315       {
1316         if (move_dir == MV_LEFT)
1317           graphic += (4 - phase4) % 4;
1318         else if (move_dir == MV_RIGHT)
1319           graphic += phase4;
1320         else
1321           graphic += phase2 * 2;
1322       }
1323       else if (element != EL_SP_INFOTRON)
1324         graphic += phase2;
1325     }
1326   }
1327 #endif
1328   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1329   {
1330     graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1331                element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1332                element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1333                element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1334                IMG_AMOEBA_DEAD_PART1);
1335
1336     graphic += (x + 2 * y + 4) % 4;
1337   }
1338
1339   if (dx || dy)
1340     DrawNewGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1341   else if (mask_mode == USE_MASKING)
1342     DrawNewGraphicThruMask(x, y, graphic, frame);
1343   else
1344     DrawNewGraphic(x, y, graphic, frame);
1345 }
1346
1347 void DrawNewLevelElementExt(int x, int y, int dx, int dy, int element,
1348                          int cut_mode, int mask_mode)
1349 {
1350   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1351     DrawNewScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1352                          cut_mode, mask_mode);
1353 }
1354
1355 void DrawNewScreenElementShifted(int x, int y, int dx, int dy, int element,
1356                               int cut_mode)
1357 {
1358   DrawNewScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1359 }
1360
1361 void DrawNewLevelElementShifted(int x, int y, int dx, int dy, int element,
1362                              int cut_mode)
1363 {
1364   DrawNewLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1365 }
1366
1367 #if 0
1368 void DrawScreenElementThruMask(int x, int y, int element)
1369 {
1370   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1371 }
1372
1373 void DrawNewScreenElementThruMask(int x, int y, int element)
1374 {
1375   DrawNewScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1376 }
1377 #endif
1378
1379 void DrawNewLevelElementThruMask(int x, int y, int element)
1380 {
1381   DrawNewLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1382 }
1383
1384 void DrawNewLevelFieldThruMask(int x, int y)
1385 {
1386   DrawNewLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1387 }
1388
1389 void DrawCrumbledSand(int x, int y)
1390 {
1391   Bitmap *src_bitmap;
1392   int src_x, src_y;
1393   int i, width, height, cx,cy;
1394   int ux = LEVELX(x), uy = LEVELY(y);
1395   int element, graphic;
1396   int snip = 4;
1397   static int xy[4][2] =
1398   {
1399     { 0, -1 },
1400     { -1, 0 },
1401     { +1, 0 },
1402     { 0, +1 }
1403   };
1404
1405   if (!IN_LEV_FIELD(ux, uy))
1406     return;
1407
1408   element = Feld[ux][uy];
1409
1410   if (element == EL_SAND ||
1411       element == EL_LANDMINE ||
1412       element == EL_TRAP ||
1413       element == EL_TRAP_ACTIVE)
1414   {
1415     if (!IN_SCR_FIELD(x, y))
1416       return;
1417
1418     graphic = IMG_SAND_CRUMBLED;
1419
1420     src_bitmap = new_graphic_info[graphic].bitmap;
1421     src_x = new_graphic_info[graphic].src_x;
1422     src_y = new_graphic_info[graphic].src_y;
1423
1424     for(i=0; i<4; i++)
1425     {
1426       int uxx, uyy;
1427
1428       uxx = ux + xy[i][0];
1429       uyy = uy + xy[i][1];
1430       if (!IN_LEV_FIELD(uxx, uyy))
1431         element = EL_STEELWALL;
1432       else
1433         element = Feld[uxx][uyy];
1434
1435       if (element == EL_SAND ||
1436           element == EL_LANDMINE ||
1437           element == EL_TRAP ||
1438           element == EL_TRAP_ACTIVE)
1439         continue;
1440
1441       if (i == 1 || i == 2)
1442       {
1443         width = snip;
1444         height = TILEY;
1445         cx = (i == 2 ? TILEX - snip : 0);
1446         cy = 0;
1447       }
1448       else
1449       {
1450         width = TILEX;
1451         height = snip;
1452         cx = 0;
1453         cy = (i == 3 ? TILEY - snip : 0);
1454       }
1455
1456       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1457                  width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1458     }
1459
1460     MarkTileDirty(x, y);
1461   }
1462   else
1463   {
1464     graphic = IMG_SAND_CRUMBLED;
1465
1466     src_bitmap = new_graphic_info[graphic].bitmap;
1467     src_x = new_graphic_info[graphic].src_x;
1468     src_y = new_graphic_info[graphic].src_y;
1469
1470     for(i=0; i<4; i++)
1471     {
1472       int xx, yy, uxx, uyy;
1473
1474       xx = x + xy[i][0];
1475       yy = y + xy[i][1];
1476       uxx = ux + xy[i][0];
1477       uyy = uy + xy[i][1];
1478
1479       if (!IN_LEV_FIELD(uxx, uyy) ||
1480           (Feld[uxx][uyy] != EL_SAND &&
1481            Feld[uxx][uyy] != EL_LANDMINE &&
1482            Feld[uxx][uyy] != EL_TRAP &&
1483            Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1484           !IN_SCR_FIELD(xx, yy))
1485         continue;
1486
1487       if (i == 1 || i == 2)
1488       {
1489         width = snip;
1490         height = TILEY;
1491         cx = (i == 1 ? TILEX - snip : 0);
1492         cy = 0;
1493       }
1494       else
1495       {
1496         width = TILEX;
1497         height = snip;
1498         cx = 0;
1499         cy = (i==0 ? TILEY-snip : 0);
1500       }
1501
1502       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1503                  width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1504
1505       MarkTileDirty(xx, yy);
1506     }
1507   }
1508 }
1509
1510 void DrawNewScreenElement(int x, int y, int element)
1511 {
1512   DrawNewScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1513   DrawCrumbledSand(x, y);
1514 }
1515
1516 void DrawNewLevelElement(int x, int y, int element)
1517 {
1518   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1519     DrawNewScreenElement(SCREENX(x), SCREENY(y), element);
1520 }
1521
1522 void DrawNewScreenField(int x, int y)
1523 {
1524   int ux = LEVELX(x), uy = LEVELY(y);
1525   int element, content;
1526
1527   if (!IN_LEV_FIELD(ux, uy))
1528   {
1529     if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1530       element = EL_EMPTY;
1531     else
1532       element = BorderElement;
1533
1534     DrawNewScreenElement(x, y, element);
1535     return;
1536   }
1537
1538   element = Feld[ux][uy];
1539   content = Store[ux][uy];
1540
1541   if (IS_MOVING(ux, uy))
1542   {
1543     int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1544     boolean cut_mode = NO_CUTTING;
1545
1546     if (element == EL_QUICKSAND_EMPTYING ||
1547         element == EL_MAGIC_WALL_EMPTYING ||
1548         element == EL_BD_MAGIC_WALL_EMPTYING ||
1549         element == EL_AMOEBA_DRIPPING)
1550       cut_mode = CUT_ABOVE;
1551     else if (element == EL_QUICKSAND_FILLING ||
1552              element == EL_MAGIC_WALL_FILLING ||
1553              element == EL_BD_MAGIC_WALL_FILLING)
1554       cut_mode = CUT_BELOW;
1555
1556     if (cut_mode == CUT_ABOVE)
1557       DrawNewScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1558     else
1559       DrawNewScreenElement(x, y, EL_EMPTY);
1560
1561     if (horiz_move)
1562       DrawNewScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1563     else if (cut_mode == NO_CUTTING)
1564       DrawNewScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1565     else
1566       DrawNewScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1567
1568     if (content == EL_ACID)
1569       DrawNewLevelElementThruMask(ux, uy + 1, EL_ACID);
1570   }
1571   else if (IS_BLOCKED(ux, uy))
1572   {
1573     int oldx, oldy;
1574     int sx, sy;
1575     int horiz_move;
1576     boolean cut_mode = NO_CUTTING;
1577     int element_old, content_old;
1578
1579     Blocked2Moving(ux, uy, &oldx, &oldy);
1580     sx = SCREENX(oldx);
1581     sy = SCREENY(oldy);
1582     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1583                   MovDir[oldx][oldy] == MV_RIGHT);
1584
1585     element_old = Feld[oldx][oldy];
1586     content_old = Store[oldx][oldy];
1587
1588     if (element_old == EL_QUICKSAND_EMPTYING ||
1589         element_old == EL_MAGIC_WALL_EMPTYING ||
1590         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1591         element_old == EL_AMOEBA_DRIPPING)
1592       cut_mode = CUT_ABOVE;
1593
1594     DrawNewScreenElement(x, y, EL_EMPTY);
1595
1596     if (horiz_move)
1597       DrawNewScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1598                                NO_CUTTING);
1599     else if (cut_mode == NO_CUTTING)
1600       DrawNewScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1601                                cut_mode);
1602     else
1603       DrawNewScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1604                                cut_mode);
1605   }
1606   else if (IS_DRAWABLE(element))
1607     DrawNewScreenElement(x, y, element);
1608   else
1609     DrawNewScreenElement(x, y, EL_EMPTY);
1610 }
1611
1612 void DrawNewLevelField(int x, int y)
1613 {
1614   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1615     DrawNewScreenField(SCREENX(x), SCREENY(y));
1616   else if (IS_MOVING(x, y))
1617   {
1618     int newx,newy;
1619
1620     Moving2Blocked(x, y, &newx, &newy);
1621     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1622       DrawNewScreenField(SCREENX(newx), SCREENY(newy));
1623   }
1624   else if (IS_BLOCKED(x, y))
1625   {
1626     int oldx, oldy;
1627
1628     Blocked2Moving(x, y, &oldx, &oldy);
1629     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1630       DrawNewScreenField(SCREENX(oldx), SCREENY(oldy));
1631   }
1632 }
1633
1634 void DrawNewMiniElement(int x, int y, int element)
1635 {
1636   int graphic;
1637
1638   graphic = el2img(element);
1639   DrawNewMiniGraphic(x, y, graphic);
1640 }
1641
1642 void DrawNewMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1643 {
1644   int x = sx + scroll_x, y = sy + scroll_y;
1645
1646   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1647     DrawNewMiniElement(sx, sy, EL_EMPTY);
1648   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1649     DrawNewMiniElement(sx, sy, Feld[x][y]);
1650   else
1651   {
1652     int steel_type, steel_position;
1653     int border[6][2] =
1654     {
1655       { IMG_STEELWALL_TOPLEFT,          IMG_INVISIBLE_STEELWALL_TOPLEFT     },
1656       { IMG_STEELWALL_TOPRIGHT,         IMG_INVISIBLE_STEELWALL_TOPRIGHT    },
1657       { IMG_STEELWALL_BOTTOMLEFT,       IMG_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1658       { IMG_STEELWALL_BOTTOMRIGHT,      IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1659       { IMG_STEELWALL_VERTICAL,         IMG_INVISIBLE_STEELWALL_VERTICAL    },
1660       { IMG_STEELWALL_HORIZONTAL,       IMG_INVISIBLE_STEELWALL_HORIZONTAL  }
1661     };
1662
1663     steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1664     steel_position = (x == -1 && y == -1                        ? 0 :
1665                       x == lev_fieldx && y == -1                ? 1 :
1666                       x == -1 && y == lev_fieldy                ? 2 :
1667                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1668                       x == -1 || x == lev_fieldx                ? 4 :
1669                       y == -1 || y == lev_fieldy                ? 5 : -1);
1670
1671     if (steel_position != -1)
1672       DrawNewMiniGraphic(sx, sy, border[steel_position][steel_type]);
1673   }
1674 }
1675
1676 void getNewMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1677 {
1678   Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1679   int mini_startx = src_bitmap->width * 3 / 4;
1680   int mini_starty = src_bitmap->height * 2 / 3;
1681   int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1682   int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1683
1684   *bitmap = src_bitmap;
1685   *x = src_x;
1686   *y = src_y;
1687 }
1688
1689 void DrawNewMicroElement(int xpos, int ypos, int element)
1690 {
1691   Bitmap *src_bitmap;
1692   int src_x, src_y;
1693   int graphic;
1694
1695   if (element == EL_EMPTY)
1696     return;
1697
1698   graphic = el2img(element);
1699
1700   getNewMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1701   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1702              xpos, ypos);
1703 }
1704
1705 void DrawLevel()
1706 {
1707   int x,y;
1708
1709   ClearWindow();
1710
1711   for(x=BX1; x<=BX2; x++)
1712     for(y=BY1; y<=BY2; y++)
1713       DrawNewScreenField(x, y);
1714
1715   redraw_mask |= REDRAW_FIELD;
1716 }
1717
1718 void DrawNewMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1719 {
1720   int x,y;
1721
1722   for(x=0; x<size_x; x++)
1723     for(y=0; y<size_y; y++)
1724       DrawNewMiniElementOrWall(x, y, scroll_x, scroll_y);
1725
1726   redraw_mask |= REDRAW_FIELD;
1727 }
1728
1729 static void DrawNewMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1730 {
1731   int x, y;
1732
1733   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1734
1735   if (lev_fieldx < STD_LEV_FIELDX)
1736     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1737   if (lev_fieldy < STD_LEV_FIELDY)
1738     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1739
1740   xpos += MICRO_TILEX;
1741   ypos += MICRO_TILEY;
1742
1743   for(x=-1; x<=STD_LEV_FIELDX; x++)
1744   {
1745     for(y=-1; y<=STD_LEV_FIELDY; y++)
1746     {
1747       int lx = from_x + x, ly = from_y + y;
1748
1749       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1750         DrawNewMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1751                             Ur[lx][ly]);
1752       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1753         DrawNewMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1754                             BorderElement);
1755     }
1756   }
1757
1758   redraw_mask |= REDRAW_MICROLEVEL;
1759 }
1760
1761 #define MICROLABEL_EMPTY                0
1762 #define MICROLABEL_LEVEL_NAME           1
1763 #define MICROLABEL_CREATED_BY           2
1764 #define MICROLABEL_LEVEL_AUTHOR         3
1765 #define MICROLABEL_IMPORTED_FROM        4
1766 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1767
1768 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1769
1770 static void DrawMicroLevelLabelExt(int mode)
1771 {
1772   char label_text[MAX_MICROLABEL_SIZE + 1];
1773
1774   ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1775
1776   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1777                        mode == MICROLABEL_CREATED_BY ? "created by" :
1778                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1779                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1780                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1781                        leveldir_current->imported_from : ""),
1782           MAX_MICROLABEL_SIZE);
1783   label_text[MAX_MICROLABEL_SIZE] = '\0';
1784
1785   if (strlen(label_text) > 0)
1786   {
1787     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1788     int lypos = MICROLABEL_YPOS;
1789
1790     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1791   }
1792
1793   redraw_mask |= REDRAW_MICROLEVEL;
1794 }
1795
1796 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1797 {
1798   static unsigned long scroll_delay = 0;
1799   static unsigned long label_delay = 0;
1800   static int from_x, from_y, scroll_direction;
1801   static int label_state, label_counter;
1802
1803   if (restart)
1804   {
1805     from_x = from_y = 0;
1806     scroll_direction = MV_RIGHT;
1807     label_state = 1;
1808     label_counter = 0;
1809
1810     DrawNewMicroLevelExt(xpos, ypos, from_x, from_y);
1811     DrawMicroLevelLabelExt(label_state);
1812
1813     /* initialize delay counters */
1814     DelayReached(&scroll_delay, 0);
1815     DelayReached(&label_delay, 0);
1816
1817     return;
1818   }
1819
1820   /* scroll micro level, if needed */
1821   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1822       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1823   {
1824     switch (scroll_direction)
1825     {
1826       case MV_LEFT:
1827         if (from_x > 0)
1828           from_x--;
1829         else
1830           scroll_direction = MV_UP;
1831         break;
1832
1833       case MV_RIGHT:
1834         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1835           from_x++;
1836         else
1837           scroll_direction = MV_DOWN;
1838         break;
1839
1840       case MV_UP:
1841         if (from_y > 0)
1842           from_y--;
1843         else
1844           scroll_direction = MV_RIGHT;
1845         break;
1846
1847       case MV_DOWN:
1848         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1849           from_y++;
1850         else
1851           scroll_direction = MV_LEFT;
1852         break;
1853
1854       default:
1855         break;
1856     }
1857
1858     DrawNewMicroLevelExt(xpos, ypos, from_x, from_y);
1859   }
1860
1861   /* redraw micro level label, if needed */
1862   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1863       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1864       strcmp(level.author, leveldir_current->name) != 0 &&
1865       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1866   {
1867     int max_label_counter = 23;
1868
1869     if (leveldir_current->imported_from != NULL)
1870       max_label_counter += 14;
1871
1872     label_counter = (label_counter + 1) % max_label_counter;
1873     label_state = (label_counter >= 0 && label_counter <= 7 ?
1874                    MICROLABEL_LEVEL_NAME :
1875                    label_counter >= 9 && label_counter <= 12 ?
1876                    MICROLABEL_CREATED_BY :
1877                    label_counter >= 14 && label_counter <= 21 ?
1878                    MICROLABEL_LEVEL_AUTHOR :
1879                    label_counter >= 23 && label_counter <= 26 ?
1880                    MICROLABEL_IMPORTED_FROM :
1881                    label_counter >= 28 && label_counter <= 35 ?
1882                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1883     DrawMicroLevelLabelExt(label_state);
1884   }
1885 }
1886
1887 int REQ_in_range(int x, int y)
1888 {
1889   if (y > DY+249 && y < DY+278)
1890   {
1891     if (x > DX+1 && x < DX+48)
1892       return 1;
1893     else if (x > DX+51 && x < DX+98) 
1894       return 2;
1895   }
1896   return 0;
1897 }
1898
1899 #define MAX_REQUEST_LINES               13
1900 #define MAX_REQUEST_LINE_LEN            7
1901
1902 boolean Request(char *text, unsigned int req_state)
1903 {
1904   int mx, my, ty, result = -1;
1905   unsigned int old_door_state;
1906
1907 #if defined(PLATFORM_UNIX)
1908   /* pause network game while waiting for request to answer */
1909   if (options.network &&
1910       game_status == PLAYING &&
1911       req_state & REQUEST_WAIT_FOR)
1912     SendToServer_PausePlaying();
1913 #endif
1914
1915   old_door_state = GetDoorState();
1916
1917   UnmapAllGadgets();
1918
1919   CloseDoor(DOOR_CLOSE_1);
1920
1921   /* save old door content */
1922   BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1923              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1924              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1925
1926   /* clear door drawing field */
1927   ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1928
1929   /* write text for request */
1930   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1931   {
1932     char text_line[MAX_REQUEST_LINE_LEN + 1];
1933     int tx, tl, tc;
1934
1935     if (!*text)
1936       break;
1937
1938     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1939     {
1940       tc = *(text + tx);
1941       if (!tc || tc == ' ')
1942         break;
1943     }
1944
1945     if (!tl)
1946     { 
1947       text++; 
1948       ty--; 
1949       continue; 
1950     }
1951
1952     strncpy(text_line, text, tl);
1953     text_line[tl] = 0;
1954
1955     DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1956                 text_line, FS_SMALL, FC_YELLOW);
1957
1958     text += tl + (tc == ' ' ? 1 : 0);
1959   }
1960
1961   if (req_state & REQ_ASK)
1962   {
1963     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1964     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1965   }
1966   else if (req_state & REQ_CONFIRM)
1967   {
1968     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1969   }
1970   else if (req_state & REQ_PLAYER)
1971   {
1972     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1973     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1974     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1975     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1976   }
1977
1978   /* copy request gadgets to door backbuffer */
1979   BlitBitmap(drawto, pix[PIX_DB_DOOR],
1980              DX, DY, DXSIZE, DYSIZE,
1981              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1982
1983   OpenDoor(DOOR_OPEN_1);
1984
1985 #if 0
1986   ClearEventQueue();
1987 #endif
1988
1989   if (!(req_state & REQUEST_WAIT_FOR))
1990     return(FALSE);
1991
1992   if (game_status != MAINMENU)
1993     InitAnimation();
1994
1995   button_status = MB_RELEASED;
1996
1997   request_gadget_id = -1;
1998
1999   while(result < 0)
2000   {
2001     if (PendingEvent())
2002     {
2003       Event event;
2004
2005       NextEvent(&event);
2006
2007       switch(event.type)
2008       {
2009         case EVENT_BUTTONPRESS:
2010         case EVENT_BUTTONRELEASE:
2011         case EVENT_MOTIONNOTIFY:
2012         {
2013           if (event.type == EVENT_MOTIONNOTIFY)
2014           {
2015             if (!PointerInWindow(window))
2016               continue; /* window and pointer are on different screens */
2017
2018             if (!button_status)
2019               continue;
2020
2021             motion_status = TRUE;
2022             mx = ((MotionEvent *) &event)->x;
2023             my = ((MotionEvent *) &event)->y;
2024           }
2025           else
2026           {
2027             motion_status = FALSE;
2028             mx = ((ButtonEvent *) &event)->x;
2029             my = ((ButtonEvent *) &event)->y;
2030             if (event.type == EVENT_BUTTONPRESS)
2031               button_status = ((ButtonEvent *) &event)->button;
2032             else
2033               button_status = MB_RELEASED;
2034           }
2035
2036           /* this sets 'request_gadget_id' */
2037           HandleGadgets(mx, my, button_status);
2038
2039           switch(request_gadget_id)
2040           {
2041             case TOOL_CTRL_ID_YES:
2042               result = TRUE;
2043               break;
2044             case TOOL_CTRL_ID_NO:
2045               result = FALSE;
2046               break;
2047             case TOOL_CTRL_ID_CONFIRM:
2048               result = TRUE | FALSE;
2049               break;
2050
2051             case TOOL_CTRL_ID_PLAYER_1:
2052               result = 1;
2053               break;
2054             case TOOL_CTRL_ID_PLAYER_2:
2055               result = 2;
2056               break;
2057             case TOOL_CTRL_ID_PLAYER_3:
2058               result = 3;
2059               break;
2060             case TOOL_CTRL_ID_PLAYER_4:
2061               result = 4;
2062               break;
2063
2064             default:
2065               break;
2066           }
2067
2068           break;
2069         }
2070
2071         case EVENT_KEYPRESS:
2072           switch(GetEventKey((KeyEvent *)&event, TRUE))
2073           {
2074             case KSYM_Return:
2075               result = 1;
2076               break;
2077
2078             case KSYM_Escape:
2079               result = 0;
2080               break;
2081
2082             default:
2083               break;
2084           }
2085           if (req_state & REQ_PLAYER)
2086             result = 0;
2087           break;
2088
2089         case EVENT_KEYRELEASE:
2090           ClearPlayerAction();
2091           break;
2092
2093         default:
2094           HandleOtherEvents(&event);
2095           break;
2096       }
2097     }
2098     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2099     {
2100       int joy = AnyJoystick();
2101
2102       if (joy & JOY_BUTTON_1)
2103         result = 1;
2104       else if (joy & JOY_BUTTON_2)
2105         result = 0;
2106     }
2107
2108     DoAnimation();
2109
2110     /* don't eat all CPU time */
2111     Delay(10);
2112   }
2113
2114   if (game_status != MAINMENU)
2115     StopAnimation();
2116
2117   UnmapToolButtons();
2118
2119   if (!(req_state & REQ_STAY_OPEN))
2120   {
2121     CloseDoor(DOOR_CLOSE_1);
2122
2123     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2124     {
2125       BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2126                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2127                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2128       OpenDoor(DOOR_OPEN_1);
2129     }
2130   }
2131
2132   RemapAllGadgets();
2133
2134 #if defined(PLATFORM_UNIX)
2135   /* continue network game after request */
2136   if (options.network &&
2137       game_status == PLAYING &&
2138       req_state & REQUEST_WAIT_FOR)
2139     SendToServer_ContinuePlaying();
2140 #endif
2141
2142   return(result);
2143 }
2144
2145 unsigned int OpenDoor(unsigned int door_state)
2146 {
2147   unsigned int new_door_state;
2148
2149   if (door_state & DOOR_COPY_BACK)
2150   {
2151     BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2152                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2153                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2154     door_state &= ~DOOR_COPY_BACK;
2155   }
2156
2157   new_door_state = MoveDoor(door_state);
2158
2159   return(new_door_state);
2160 }
2161
2162 unsigned int CloseDoor(unsigned int door_state)
2163 {
2164   unsigned int new_door_state;
2165
2166   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2167              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2168   BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2169              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2170
2171   new_door_state = MoveDoor(door_state);
2172
2173   return(new_door_state);
2174 }
2175
2176 unsigned int GetDoorState()
2177 {
2178   return MoveDoor(DOOR_GET_STATE);
2179 }
2180
2181 unsigned int SetDoorState(unsigned int door_state)
2182 {
2183   return MoveDoor(door_state | DOOR_SET_STATE);
2184 }
2185
2186 unsigned int MoveDoor(unsigned int door_state)
2187 {
2188   static int door1 = DOOR_OPEN_1;
2189   static int door2 = DOOR_CLOSE_2;
2190   static unsigned long door_delay = 0;
2191   int x, start, stepsize = 2;
2192   unsigned long door_delay_value = stepsize * 5;
2193
2194   if (door_state == DOOR_GET_STATE)
2195     return(door1 | door2);
2196
2197   if (door_state & DOOR_SET_STATE)
2198   {
2199     if (door_state & DOOR_ACTION_1)
2200       door1 = door_state & DOOR_ACTION_1;
2201     if (door_state & DOOR_ACTION_2)
2202       door2 = door_state & DOOR_ACTION_2;
2203
2204     return(door1 | door2);
2205   }
2206
2207   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2208     door_state &= ~DOOR_OPEN_1;
2209   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2210     door_state &= ~DOOR_CLOSE_1;
2211   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2212     door_state &= ~DOOR_OPEN_2;
2213   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2214     door_state &= ~DOOR_CLOSE_2;
2215
2216   if (setup.quick_doors)
2217   {
2218     stepsize = 20;
2219     door_delay_value = 0;
2220     StopSound(SND_MENU_DOOR_OPENING);
2221     StopSound(SND_MENU_DOOR_CLOSING);
2222   }
2223
2224   if (door_state & DOOR_ACTION)
2225   {
2226     if (!(door_state & DOOR_NO_DELAY))
2227     {
2228       /* opening door sound has priority over simultaneously closing door */
2229       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2230         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2231       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2232         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2233     }
2234
2235     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2236
2237     for(x=start; x<=DXSIZE; x+=stepsize)
2238     {
2239       Bitmap *bitmap = pix[PIX_DOOR];
2240       GC gc = bitmap->stored_clip_gc;
2241
2242       WaitUntilDelayReached(&door_delay, door_delay_value);
2243
2244       if (door_state & DOOR_ACTION_1)
2245       {
2246         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2247         int j = (DXSIZE - i) / 3;
2248
2249         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2250                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2251                    DXSIZE,DYSIZE - i/2, DX, DY);
2252
2253         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2254
2255         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2256         BlitBitmapMasked(bitmap, drawto,
2257                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2258                          DX + DXSIZE - i, DY + j);
2259         BlitBitmapMasked(bitmap, drawto,
2260                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2261                          DX + DXSIZE - i, DY + 140 + j);
2262         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2263         BlitBitmapMasked(bitmap, drawto,
2264                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2265                          DX, DY);
2266         BlitBitmapMasked(bitmap, drawto,
2267                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2268                          DX, DY + 140 - j);
2269
2270         BlitBitmapMasked(bitmap, drawto,
2271                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2272                          DX, DY + 77 - j);
2273         BlitBitmapMasked(bitmap, drawto,
2274                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2275                          DX, DY + 203 - j);
2276         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2277         BlitBitmapMasked(bitmap, drawto,
2278                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2279                          DX + DXSIZE - i, DY + 77 + j);
2280         BlitBitmapMasked(bitmap, drawto,
2281                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2282                          DX + DXSIZE - i, DY + 203 + j);
2283
2284         redraw_mask |= REDRAW_DOOR_1;
2285       }
2286
2287       if (door_state & DOOR_ACTION_2)
2288       {
2289         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2290         int j = (VXSIZE - i) / 3;
2291
2292         BlitBitmap(pix[PIX_DB_DOOR], drawto,
2293                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2294                    VXSIZE, VYSIZE - i/2, VX, VY);
2295
2296         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2297
2298         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2299         BlitBitmapMasked(bitmap, drawto,
2300                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2301                          VX + VXSIZE-i, VY+j);
2302         SetClipOrigin(bitmap, gc,
2303                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2304         BlitBitmapMasked(bitmap, drawto,
2305                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2306                          VX, VY);
2307
2308         BlitBitmapMasked(bitmap, drawto,
2309                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2310                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2311         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2312         BlitBitmapMasked(bitmap, drawto,
2313                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2314                          i, VYSIZE / 2 - j,
2315                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2316
2317         redraw_mask |= REDRAW_DOOR_2;
2318       }
2319
2320       BackToFront();
2321
2322       if (game_status == MAINMENU)
2323         DoAnimation();
2324     }
2325   }
2326
2327   if (setup.quick_doors)
2328   {
2329     StopSound(SND_MENU_DOOR_OPENING);
2330     StopSound(SND_MENU_DOOR_CLOSING);
2331   }
2332
2333   if (door_state & DOOR_ACTION_1)
2334     door1 = door_state & DOOR_ACTION_1;
2335   if (door_state & DOOR_ACTION_2)
2336     door2 = door_state & DOOR_ACTION_2;
2337
2338   return (door1 | door2);
2339 }
2340
2341 void DrawSpecialEditorDoor()
2342 {
2343   /* draw bigger toolbox window */
2344   BlitBitmap(pix[PIX_DOOR], drawto,
2345              DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2346
2347   redraw_mask |= REDRAW_ALL;
2348 }
2349
2350 void UndrawSpecialEditorDoor()
2351 {
2352   /* draw normal tape recorder window */
2353   BlitBitmap(pix[PIX_BACK], drawto,
2354              562, 344, 108, 56, EX - 4, EY - 12);
2355
2356   redraw_mask |= REDRAW_ALL;
2357 }
2358
2359 #ifndef TARGET_SDL
2360 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2361 {
2362   XImage *pixel_image;
2363   unsigned long pixel_value;
2364
2365   pixel_image = XGetImage(display, bitmap->drawable,
2366                           x, y, 1, 1, AllPlanes, ZPixmap);
2367   pixel_value = XGetPixel(pixel_image, 0, 0);
2368
2369   XDestroyImage(pixel_image);
2370
2371   return pixel_value;
2372 }
2373 #endif
2374
2375 /* ---------- new tool button stuff ---------------------------------------- */
2376
2377 /* graphic position values for tool buttons */
2378 #define TOOL_BUTTON_YES_XPOS            2
2379 #define TOOL_BUTTON_YES_YPOS            250
2380 #define TOOL_BUTTON_YES_GFX_YPOS        0
2381 #define TOOL_BUTTON_YES_XSIZE           46
2382 #define TOOL_BUTTON_YES_YSIZE           28
2383 #define TOOL_BUTTON_NO_XPOS             52
2384 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2385 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2386 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2387 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2388 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2389 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2390 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2391 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2392 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2393 #define TOOL_BUTTON_PLAYER_XSIZE        30
2394 #define TOOL_BUTTON_PLAYER_YSIZE        30
2395 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2396 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2397 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2398 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2399 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2400                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2401 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2402                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2403 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2404                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2405 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2406                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2407 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2408                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2409 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2410                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2411 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2412                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2413 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2414                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2415
2416 static struct
2417 {
2418   int xpos, ypos;
2419   int x, y;
2420   int width, height;
2421   int gadget_id;
2422   char *infotext;
2423 } toolbutton_info[NUM_TOOL_BUTTONS] =
2424 {
2425   {
2426     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2427     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2428     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2429     TOOL_CTRL_ID_YES,
2430     "yes"
2431   },
2432   {
2433     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2434     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2435     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2436     TOOL_CTRL_ID_NO,
2437     "no"
2438   },
2439   {
2440     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2441     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2442     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2443     TOOL_CTRL_ID_CONFIRM,
2444     "confirm"
2445   },
2446   {
2447     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2448     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2449     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2450     TOOL_CTRL_ID_PLAYER_1,
2451     "player 1"
2452   },
2453   {
2454     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2455     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2456     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2457     TOOL_CTRL_ID_PLAYER_2,
2458     "player 2"
2459   },
2460   {
2461     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2462     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2463     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2464     TOOL_CTRL_ID_PLAYER_3,
2465     "player 3"
2466   },
2467   {
2468     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2469     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2470     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2471     TOOL_CTRL_ID_PLAYER_4,
2472     "player 4"
2473   }
2474 };
2475
2476 void CreateToolButtons()
2477 {
2478   int i;
2479
2480   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2481   {
2482     Bitmap *gd_bitmap = pix[PIX_DOOR];
2483     Bitmap *deco_bitmap = None;
2484     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2485     struct GadgetInfo *gi;
2486     unsigned long event_mask;
2487     int gd_xoffset, gd_yoffset;
2488     int gd_x1, gd_x2, gd_y;
2489     int id = i;
2490
2491     event_mask = GD_EVENT_RELEASED;
2492
2493     gd_xoffset = toolbutton_info[i].xpos;
2494     gd_yoffset = toolbutton_info[i].ypos;
2495     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2496     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2497     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2498
2499     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2500     {
2501       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2502
2503       getNewMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2504                               &deco_bitmap, &deco_x, &deco_y);
2505       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2506       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2507     }
2508
2509     gi = CreateGadget(GDI_CUSTOM_ID, id,
2510                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2511                       GDI_X, DX + toolbutton_info[i].x,
2512                       GDI_Y, DY + toolbutton_info[i].y,
2513                       GDI_WIDTH, toolbutton_info[i].width,
2514                       GDI_HEIGHT, toolbutton_info[i].height,
2515                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2516                       GDI_STATE, GD_BUTTON_UNPRESSED,
2517                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2518                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2519                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2520                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2521                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2522                       GDI_DECORATION_SHIFTING, 1, 1,
2523                       GDI_EVENT_MASK, event_mask,
2524                       GDI_CALLBACK_ACTION, HandleToolButtons,
2525                       GDI_END);
2526
2527     if (gi == NULL)
2528       Error(ERR_EXIT, "cannot create gadget");
2529
2530     tool_gadget[id] = gi;
2531   }
2532 }
2533
2534 static void UnmapToolButtons()
2535 {
2536   int i;
2537
2538   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2539     UnmapGadget(tool_gadget[i]);
2540 }
2541
2542 static void HandleToolButtons(struct GadgetInfo *gi)
2543 {
2544   request_gadget_id = gi->custom_id;
2545 }
2546
2547 int get_next_element(int element)
2548 {
2549   switch(element)
2550   {
2551     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
2552     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
2553     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
2554     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
2555     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
2556     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
2557     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
2558
2559     default:                            return element;
2560   }
2561 }
2562
2563 int el2gfx_OLD(int element)
2564 {
2565   switch(element)
2566   {
2567     case EL_EMPTY:                      return -1;
2568     case EL_SAND:                       return GFX_ERDREICH;
2569     case EL_WALL:                       return GFX_MAUERWERK;
2570     case EL_WALL_CRUMBLED:              return GFX_FELSBODEN;
2571     case EL_ROCK:                       return GFX_FELSBROCKEN;
2572     case EL_EMERALD:                    return GFX_EDELSTEIN;
2573     case EL_EXIT_CLOSED:                return GFX_AUSGANG_ZU;
2574     case EL_EXIT_OPENING:               return GFX_AUSGANG_ACT;
2575     case EL_EXIT_OPEN:                  return GFX_AUSGANG_AUF;
2576     case EL_SP_EXIT_OPEN:               return GFX_SP_EXIT;
2577     case EL_PLAYER1:                    return GFX_SPIELER1;
2578     case EL_PLAYER2:                    return GFX_SPIELER2;
2579     case EL_PLAYER3:                    return GFX_SPIELER3;
2580     case EL_PLAYER4:                    return GFX_SPIELER4;
2581     case EL_BUG:                        return GFX_KAEFER;
2582     case EL_BUG_RIGHT:                  return GFX_KAEFER_RIGHT;
2583     case EL_BUG_UP:                     return GFX_KAEFER_UP;
2584     case EL_BUG_LEFT:                   return GFX_KAEFER_LEFT;
2585     case EL_BUG_DOWN:                   return GFX_KAEFER_DOWN;
2586     case EL_SPACESHIP:                  return GFX_FLIEGER;
2587     case EL_SPACESHIP_RIGHT:            return GFX_FLIEGER_RIGHT;
2588     case EL_SPACESHIP_UP:               return GFX_FLIEGER_UP;
2589     case EL_SPACESHIP_LEFT:             return GFX_FLIEGER_LEFT;
2590     case EL_SPACESHIP_DOWN:             return GFX_FLIEGER_DOWN;
2591     case EL_BD_BUTTERFLY:               return GFX_BUTTERFLY;
2592     case EL_BD_BUTTERFLY_RIGHT:         return GFX_BUTTERFLY_RIGHT;
2593     case EL_BD_BUTTERFLY_UP:            return GFX_BUTTERFLY_UP;
2594     case EL_BD_BUTTERFLY_LEFT:          return GFX_BUTTERFLY_LEFT;
2595     case EL_BD_BUTTERFLY_DOWN:          return GFX_BUTTERFLY_DOWN;
2596     case EL_BD_FIREFLY:                 return GFX_FIREFLY;
2597     case EL_BD_FIREFLY_RIGHT:           return GFX_FIREFLY_RIGHT;
2598     case EL_BD_FIREFLY_UP:              return GFX_FIREFLY_UP;
2599     case EL_BD_FIREFLY_LEFT:            return GFX_FIREFLY_LEFT;
2600     case EL_BD_FIREFLY_DOWN:            return GFX_FIREFLY_DOWN;
2601     case EL_YAMYAM:                     return GFX_MAMPFER;
2602     case EL_ROBOT:                      return GFX_ROBOT;
2603     case EL_STEELWALL:                  return GFX_BETON;
2604     case EL_DIAMOND:                    return GFX_DIAMANT;
2605     case EL_QUICKSAND_EMPTY:            return GFX_MORAST_LEER;
2606     case EL_QUICKSAND_FULL:             return GFX_MORAST_VOLL;
2607     case EL_QUICKSAND_EMPTYING:         return GFX_MORAST_LEER;
2608     case EL_AMOEBA_DROP:                return GFX_TROPFEN;
2609     case EL_BOMB:                       return GFX_BOMBE;
2610     case EL_MAGIC_WALL:                 return GFX_MAGIC_WALL_OFF;
2611     case EL_MAGIC_WALL_ACTIVE:          return GFX_MAGIC_WALL_EMPTY;
2612     case EL_MAGIC_WALL_EMPTYING:        return GFX_MAGIC_WALL_EMPTY;
2613     case EL_MAGIC_WALL_FULL:            return GFX_MAGIC_WALL_FULL;
2614     case EL_MAGIC_WALL_DEAD:            return GFX_MAGIC_WALL_DEAD;
2615     case EL_ACID:                       return GFX_SALZSAEURE;
2616     case EL_AMOEBA_DEAD:                return GFX_AMOEBE_TOT;
2617     case EL_AMOEBA_WET:                 return GFX_AMOEBE_NASS;
2618     case EL_AMOEBA_DRY:                 return GFX_AMOEBE_NORM;
2619     case EL_AMOEBA_FULL:                return GFX_AMOEBE_VOLL;
2620     case EL_BD_AMOEBA:                  return GFX_AMOEBE_BD;
2621     case EL_AMOEBA_TO_DIAMOND:          return GFX_AMOEBA2DIAM;
2622     case EL_AMOEBA_DRIPPING:            return GFX_AMOEBE_NASS;
2623     case EL_NUT:                        return GFX_KOKOSNUSS;
2624     case EL_GAMEOFLIFE:                 return GFX_LIFE;
2625     case EL_BIOMAZE:                    return GFX_LIFE_ASYNC;
2626     case EL_DYNAMITE_ACTIVE:            return GFX_DYNAMIT;
2627     case EL_STONEBLOCK:                 return GFX_BADEWANNE;
2628     case EL_ACIDPOOL_TOPLEFT:           return GFX_BADEWANNE1;
2629     case EL_ACIDPOOL_TOPRIGHT:          return GFX_BADEWANNE2;
2630     case EL_ACIDPOOL_BOTTOMLEFT:        return GFX_BADEWANNE3;
2631     case EL_ACIDPOOL_BOTTOM:            return GFX_BADEWANNE4;
2632     case EL_ACIDPOOL_BOTTOMRIGHT:       return GFX_BADEWANNE5;
2633     case EL_ROBOT_WHEEL:                return GFX_ABLENK_AUS;
2634     case EL_ROBOT_WHEEL_ACTIVE:         return GFX_ABLENK_EIN;
2635     case EL_KEY1:                       return GFX_SCHLUESSEL1;
2636     case EL_KEY2:                       return GFX_SCHLUESSEL2;
2637     case EL_KEY3:                       return GFX_SCHLUESSEL3;
2638     case EL_KEY4:                       return GFX_SCHLUESSEL4;
2639     case EL_GATE1:                      return GFX_PFORTE1;
2640     case EL_GATE2:                      return GFX_PFORTE2;
2641     case EL_GATE3:                      return GFX_PFORTE3;
2642     case EL_GATE4:                      return GFX_PFORTE4;
2643     case EL_GATE1_GRAY:                 return GFX_PFORTE1X;
2644     case EL_GATE2_GRAY:                 return GFX_PFORTE2X;
2645     case EL_GATE3_GRAY:                 return GFX_PFORTE3X;
2646     case EL_GATE4_GRAY:                 return GFX_PFORTE4X;
2647     case EL_DYNAMITE:                   return GFX_DYNAMIT_AUS;
2648     case EL_PACMAN:                     return GFX_PACMAN;
2649     case EL_PACMAN_RIGHT:               return GFX_PACMAN_RIGHT;
2650     case EL_PACMAN_UP:                  return GFX_PACMAN_UP;
2651     case EL_PACMAN_LEFT:                return GFX_PACMAN_LEFT;
2652     case EL_PACMAN_DOWN:                return GFX_PACMAN_DOWN;
2653     case EL_INVISIBLE_WALL:             return GFX_UNSICHTBAR;
2654     case EL_INVISIBLE_WALL_ACTIVE:      return GFX_UNSICHTBAR_ON;
2655     case EL_WALL_EMERALD:               return GFX_ERZ_EDEL;
2656     case EL_WALL_DIAMOND:               return GFX_ERZ_DIAM;
2657     case EL_LAMP:                       return GFX_BIRNE_AUS;
2658     case EL_LAMP_ACTIVE:                return GFX_BIRNE_EIN;
2659     case EL_TIME_ORB_FULL:              return GFX_ZEIT_VOLL;
2660     case EL_TIME_ORB_EMPTY:             return GFX_ZEIT_LEER;
2661     case EL_WALL_GROWING:               return GFX_MAUER_LEBT;
2662     case EL_WALL_GROWING_X:             return GFX_MAUER_X;
2663     case EL_WALL_GROWING_Y:             return GFX_MAUER_Y;
2664     case EL_WALL_GROWING_XY:            return GFX_MAUER_XY;
2665     case EL_BD_DIAMOND:                 return GFX_EDELSTEIN_BD;
2666     case EL_EMERALD_YELLOW:             return GFX_EDELSTEIN_GELB;
2667     case EL_EMERALD_RED:                return GFX_EDELSTEIN_ROT;
2668     case EL_EMERALD_PURPLE:             return GFX_EDELSTEIN_LILA;
2669     case EL_WALL_BD_DIAMOND:            return GFX_ERZ_EDEL_BD;
2670     case EL_WALL_EMERALD_YELLOW:        return GFX_ERZ_EDEL_GELB;
2671     case EL_WALL_EMERALD_RED:           return GFX_ERZ_EDEL_ROT;
2672     case EL_WALL_EMERALD_PURPLE:        return GFX_ERZ_EDEL_LILA;
2673     case EL_DARK_YAMYAM:                return GFX_MAMPFER2;
2674     case EL_BD_MAGIC_WALL:              return GFX_MAGIC_WALL_BD_OFF;
2675     case EL_BD_MAGIC_WALL_ACTIVE:       return GFX_MAGIC_WALL_BD_EMPTY;
2676     case EL_BD_MAGIC_WALL_EMPTYING:     return GFX_MAGIC_WALL_BD_EMPTY;
2677     case EL_BD_MAGIC_WALL_FULL:         return GFX_MAGIC_WALL_BD_FULL;
2678     case EL_BD_MAGIC_WALL_DEAD:         return GFX_MAGIC_WALL_BD_DEAD;
2679     case EL_DYNABOMB_PLAYER1_ACTIVE:    return GFX_DYNABOMB;
2680     case EL_DYNABOMB_PLAYER2_ACTIVE:    return GFX_DYNABOMB;
2681     case EL_DYNABOMB_PLAYER3_ACTIVE:    return GFX_DYNABOMB;
2682     case EL_DYNABOMB_PLAYER4_ACTIVE:    return GFX_DYNABOMB;
2683     case EL_DYNABOMB_NR:                return GFX_DYNABOMB_NR;
2684     case EL_DYNABOMB_SZ:                return GFX_DYNABOMB_SZ;
2685     case EL_DYNABOMB_XL:                return GFX_DYNABOMB_XL;
2686     case EL_SOKOBAN_OBJECT:             return GFX_SOKOBAN_OBJEKT;
2687     case EL_SOKOBAN_FIELD_EMPTY:        return GFX_SOKOBAN_FELD_LEER;
2688     case EL_SOKOBAN_FIELD_FULL:         return GFX_SOKOBAN_FELD_VOLL;
2689     case EL_MOLE:                       return GFX_MOLE;
2690     case EL_PENGUIN:                    return GFX_PINGUIN;
2691     case EL_PIG:                        return GFX_SCHWEIN;
2692     case EL_DRAGON:                     return GFX_DRACHE;
2693     case EL_SATELLITE:                  return GFX_SONDE;
2694     case EL_ARROW_BLUE_LEFT:            return GFX_PFEIL_LEFT;
2695     case EL_ARROW_BLUE_RIGHT:           return GFX_PFEIL_RIGHT;
2696     case EL_ARROW_BLUE_UP:              return GFX_PFEIL_UP;
2697     case EL_ARROW_BLUE_DOWN:            return GFX_PFEIL_DOWN;
2698     case EL_SPEED_PILL:                 return GFX_SPEED_PILL;
2699     case EL_SP_TERMINAL_ACTIVE:         return GFX_SP_TERMINAL;
2700     case EL_SP_BUGGY_BASE_ACTIVE:       return GFX_SP_BUG_ACTIVE;
2701     case EL_SP_ZONK:                    return GFX_SP_ZONK;
2702       /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2703     case EL_INVISIBLE_STEELWALL:        return GFX_INVISIBLE_STEEL;
2704     case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2705     case EL_BLACK_ORB:                  return GFX_BLACK_ORB;
2706     case EL_EM_GATE1:                   return GFX_EM_GATE_1;
2707     case EL_EM_GATE2:                   return GFX_EM_GATE_2;
2708     case EL_EM_GATE3:                   return GFX_EM_GATE_3;
2709     case EL_EM_GATE4:                   return GFX_EM_GATE_4;
2710     case EL_EM_GATE1_GRAY:              return GFX_EM_GATE_1X;
2711     case EL_EM_GATE2_GRAY:              return GFX_EM_GATE_2X;
2712     case EL_EM_GATE3_GRAY:              return GFX_EM_GATE_3X;
2713     case EL_EM_GATE4_GRAY:              return GFX_EM_GATE_4X;
2714     case EL_EM_KEY1_FILE:               return GFX_EM_KEY_1;
2715     case EL_EM_KEY2_FILE:               return GFX_EM_KEY_2;
2716     case EL_EM_KEY3_FILE:               return GFX_EM_KEY_3;
2717     case EL_EM_KEY4_FILE:               return GFX_EM_KEY_4;
2718     case EL_EM_KEY1:                    return GFX_EM_KEY_1;
2719     case EL_EM_KEY2:                    return GFX_EM_KEY_2;
2720     case EL_EM_KEY3:                    return GFX_EM_KEY_3;
2721     case EL_EM_KEY4:                    return GFX_EM_KEY_4;
2722     case EL_PEARL:                      return GFX_PEARL;
2723     case EL_CRYSTAL:                    return GFX_CRYSTAL;
2724     case EL_WALL_PEARL:                 return GFX_WALL_PEARL;
2725     case EL_WALL_CRYSTAL:               return GFX_WALL_CRYSTAL;
2726     case EL_DOOR_WHITE:                 return GFX_DOOR_WHITE;
2727     case EL_DOOR_WHITE_GRAY:            return GFX_DOOR_WHITE_GRAY;
2728     case EL_KEY_WHITE:                  return GFX_KEY_WHITE;
2729     case EL_SHIELD_NORMAL:              return GFX_SHIELD_PASSIVE;
2730     case EL_SHIELD_DEADLY:              return GFX_SHIELD_ACTIVE;
2731     case EL_EXTRA_TIME:                 return GFX_EXTRA_TIME;
2732     case EL_SWITCHGATE_OPEN:            return GFX_SWITCHGATE_OPEN;
2733     case EL_SWITCHGATE_CLOSED:          return GFX_SWITCHGATE_CLOSED;
2734     case EL_SWITCHGATE_SWITCH_UP:       return GFX_SWITCHGATE_SWITCH_1;
2735     case EL_SWITCHGATE_SWITCH_DOWN:     return GFX_SWITCHGATE_SWITCH_2;
2736     case EL_CONVEYOR_BELT1_LEFT:        return GFX_BELT1_LEFT;
2737     case EL_CONVEYOR_BELT1_MIDDLE:      return GFX_BELT1_MIDDLE;
2738     case EL_CONVEYOR_BELT1_RIGHT:       return GFX_BELT1_RIGHT;
2739     case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2740     case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2741     case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2742     case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2743     case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2744     case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2745     case EL_CONVEYOR_BELT2_LEFT:        return GFX_BELT2_LEFT;
2746     case EL_CONVEYOR_BELT2_MIDDLE:      return GFX_BELT2_MIDDLE;
2747     case EL_CONVEYOR_BELT2_RIGHT:       return GFX_BELT2_RIGHT;
2748     case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2749     case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2750     case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2751     case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2752     case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2753     case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2754     case EL_CONVEYOR_BELT3_LEFT:        return GFX_BELT3_LEFT;
2755     case EL_CONVEYOR_BELT3_MIDDLE:      return GFX_BELT3_MIDDLE;
2756     case EL_CONVEYOR_BELT3_RIGHT:       return GFX_BELT3_RIGHT;
2757     case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2758     case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2759     case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2760     case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2761     case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2762     case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2763     case EL_CONVEYOR_BELT4_LEFT:        return GFX_BELT4_LEFT;
2764     case EL_CONVEYOR_BELT4_MIDDLE:      return GFX_BELT4_MIDDLE;
2765     case EL_CONVEYOR_BELT4_RIGHT:       return GFX_BELT4_RIGHT;
2766     case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2767     case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2768     case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2769     case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2770     case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2771     case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2772     case EL_LANDMINE:                   return GFX_LANDMINE;
2773     case EL_ENVELOPE:                   return GFX_ENVELOPE;
2774     case EL_LIGHT_SWITCH:               return GFX_LIGHT_SWITCH_OFF;
2775     case EL_LIGHT_SWITCH_ACTIVE:        return GFX_LIGHT_SWITCH_ON;
2776     case EL_SIGN_EXCLAMATION:           return GFX_SIGN_EXCLAMATION;
2777     case EL_SIGN_RADIOACTIVITY:         return GFX_SIGN_RADIOACTIVITY;
2778     case EL_SIGN_STOP:                  return GFX_SIGN_STOP;
2779     case EL_SIGN_WHEELCHAIR:            return GFX_SIGN_WHEELCHAIR;
2780     case EL_SIGN_PARKING:               return GFX_SIGN_PARKING;
2781     case EL_SIGN_ONEWAY:                return GFX_SIGN_ONEWAY;
2782     case EL_SIGN_HEART:                 return GFX_SIGN_HEART;
2783     case EL_SIGN_TRIANGLE:              return GFX_SIGN_TRIANGLE;
2784     case EL_SIGN_ROUND:                 return GFX_SIGN_ROUND;
2785     case EL_SIGN_EXIT:                  return GFX_SIGN_EXIT;
2786     case EL_SIGN_YINYANG:               return GFX_SIGN_YINYANG;
2787     case EL_SIGN_OTHER:                 return GFX_SIGN_OTHER;
2788     case EL_MOLE_LEFT:                  return GFX_MOLE_LEFT;
2789     case EL_MOLE_RIGHT:                 return GFX_MOLE_RIGHT;
2790     case EL_MOLE_UP:                    return GFX_MOLE_UP;
2791     case EL_MOLE_DOWN:                  return GFX_MOLE_DOWN;
2792     case EL_STEELWALL_SLANTED:          return GFX_STEEL_SLANTED;
2793     case EL_INVISIBLE_SAND:             return GFX_SAND_INVISIBLE;
2794     case EL_INVISIBLE_SAND_ACTIVE:      return GFX_SAND_INVISIBLE_ON;
2795     case EL_DX_UNKNOWN_15:              return GFX_DX_UNKNOWN_15;
2796     case EL_DX_UNKNOWN_42:              return GFX_DX_UNKNOWN_42;
2797     case EL_TIMEGATE_OPEN:              return GFX_TIMEGATE_OPEN;
2798     case EL_TIMEGATE_CLOSED:            return GFX_TIMEGATE_CLOSED;
2799     case EL_TIMEGATE_SWITCH_ACTIVE:     return GFX_TIMEGATE_SWITCH;
2800     case EL_TIMEGATE_SWITCH:            return GFX_TIMEGATE_SWITCH;
2801     case EL_BALLOON:                    return GFX_BALLOON;
2802     case EL_BALLOON_SEND_LEFT:          return GFX_BALLOON_SEND_LEFT;
2803     case EL_BALLOON_SEND_RIGHT:         return GFX_BALLOON_SEND_RIGHT;
2804     case EL_BALLOON_SEND_UP:            return GFX_BALLOON_SEND_UP;
2805     case EL_BALLOON_SEND_DOWN:          return GFX_BALLOON_SEND_DOWN;
2806     case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2807     case EL_EMC_STEELWALL1:             return GFX_EMC_STEEL_WALL_1;
2808     case EL_EMC_STEELWALL2:             return GFX_EMC_STEEL_WALL_2;
2809     case EL_EMC_STEELWALL3:             return GFX_EMC_STEEL_WALL_3;
2810     case EL_EMC_STEELWALL4:             return GFX_EMC_STEEL_WALL_4;
2811     case EL_EMC_WALL_PILLAR_UPPER:      return GFX_EMC_WALL_1;
2812     case EL_EMC_WALL_PILLAR_MIDDLE:     return GFX_EMC_WALL_2;
2813     case EL_EMC_WALL_PILLAR_LOWER:      return GFX_EMC_WALL_3;
2814     case EL_EMC_WALL4:                  return GFX_EMC_WALL_4;
2815     case EL_EMC_WALL5:                  return GFX_EMC_WALL_5;
2816     case EL_EMC_WALL6:                  return GFX_EMC_WALL_6;
2817     case EL_EMC_WALL7:                  return GFX_EMC_WALL_7;
2818     case EL_EMC_WALL8:                  return GFX_EMC_WALL_8;
2819     case EL_TUBE_ALL:                   return GFX_TUBE_CROSS;
2820     case EL_TUBE_VERTICAL:              return GFX_TUBE_VERTICAL;
2821     case EL_TUBE_HORIZONTAL:            return GFX_TUBE_HORIZONTAL;
2822     case EL_TUBE_VERTICAL_LEFT:         return GFX_TUBE_VERT_LEFT;
2823     case EL_TUBE_VERTICAL_RIGHT:        return GFX_TUBE_VERT_RIGHT;
2824     case EL_TUBE_HORIZONTAL_UP:         return GFX_TUBE_HORIZ_UP;
2825     case EL_TUBE_HORIZONTAL_DOWN:       return GFX_TUBE_HORIZ_DOWN;
2826     case EL_TUBE_LEFT_UP:               return GFX_TUBE_LEFT_UP;
2827     case EL_TUBE_LEFT_DOWN:             return GFX_TUBE_LEFT_DOWN;
2828     case EL_TUBE_RIGHT_UP:              return GFX_TUBE_RIGHT_UP;
2829     case EL_TUBE_RIGHT_DOWN:            return GFX_TUBE_RIGHT_DOWN;
2830     case EL_SPRING:                     return GFX_SPRING;
2831     case EL_SPRING_MOVING:              return GFX_SPRING;
2832     case EL_TRAP:                       return GFX_TRAP_INACTIVE;
2833     case EL_TRAP_ACTIVE:                return GFX_TRAP_ACTIVE;
2834     case EL_BD_WALL:                    return GFX_BD_WALL;
2835     case EL_BD_ROCK:                    return GFX_BD_ROCK;
2836     case EL_DX_SUPABOMB:                return GFX_DX_SUPABOMB;
2837     case EL_SP_MURPHY_CLONE:            return GFX_SP_MURPHY_CLONE;
2838
2839     default:
2840     {
2841       if (IS_CHAR(element))
2842         return GFX_CHAR_START + (element - EL_CHAR_START);
2843       else if (element >= EL_SP_START && element <= EL_SP_END)
2844       {
2845         int nr_element = element - EL_SP_START;
2846         int gfx_per_line = 8;
2847         int nr_graphic =
2848           (nr_element / gfx_per_line) * SP_PER_LINE +
2849           (nr_element % gfx_per_line);
2850
2851         return GFX_START_ROCKSSP + nr_graphic;
2852       }
2853       else
2854         return -1;
2855     }
2856   }
2857 }
2858
2859 int el2gfx(int element)
2860 {
2861 #if 1
2862   int graphic_OLD = el2gfx_OLD(element);
2863
2864   return graphic_OLD;
2865 #else
2866
2867   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2868
2869 #if DEBUG
2870   int graphic_OLD = el2gfx_OLD(element);
2871
2872   if (element >= MAX_ELEMENTS)
2873   {
2874     Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2875   }
2876
2877   if (graphic_NEW != graphic_OLD)
2878   {
2879     Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2880           graphic_NEW, graphic_OLD);
2881   }
2882 #endif
2883
2884   return graphic_NEW;
2885 #endif
2886 }
2887
2888 int el2img(int element)
2889 {
2890 #if 1
2891   int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2892
2893 #if DEBUG
2894   if (graphic_NEW < 0)
2895     Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2896           element, graphic_NEW);
2897 #endif
2898
2899   return graphic_NEW;
2900 #else
2901
2902   switch(element)
2903   {
2904     case EL_BD_BUTTERFLY:       return IMG_BD_BUTTERFLY;
2905     case EL_BD_FIREFLY:         return IMG_BD_FIREFLY;
2906     case EL_SP_ELECTRON:        return IMG_SP_ELECTRON;
2907
2908     default:
2909       break;
2910   }
2911
2912   return IMG_EMPTY;
2913 #endif
2914 }
2915
2916 int el_dir2img(int element, int direction)
2917 {
2918   return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2919 }
2920
2921 int el_dir_act2img(int element, int direction, int action)
2922 {
2923   action = graphics_action_mapping[action];
2924   direction = MV_DIR_BIT(direction);
2925
2926   return element_info[element].direction_graphic[action][direction];
2927 }