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