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