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