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