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