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