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