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