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