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