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