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