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