5722e2528137a59a47f4b0bca72baf29a2795879
[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                           graphic_info[graphic].bitmap ?
369                           graphic_info[graphic].bitmap :
370                           graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
371 }
372
373 void SetDoorBackgroundImage(int graphic)
374 {
375   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376                           graphic_info[graphic].bitmap ?
377                           graphic_info[graphic].bitmap :
378                           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 void MarkTileDirty(int x, int y)
408 {
409   int xx = redraw_x1 + x;
410   int yy = redraw_y1 + y;
411
412   if (!redraw[xx][yy])
413     redraw_tiles++;
414
415   redraw[xx][yy] = TRUE;
416   redraw_mask |= REDRAW_TILES;
417 }
418
419 void SetBorderElement()
420 {
421   int x, y;
422
423   BorderElement = EL_EMPTY;
424
425   for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
426   {
427     for(x=0; x<lev_fieldx; x++)
428     {
429       if (!IS_MASSIVE(Feld[x][y]))
430         BorderElement = EL_STEELWALL;
431
432       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
433         x = lev_fieldx - 2;
434     }
435   }
436 }
437
438 void SetRandomAnimationValue(int x, int y)
439 {
440   anim.random_frame = GfxRandom[x][y];
441 }
442
443 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
444 {
445   /* animation synchronized with global frame counter, not move position */
446   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
447     sync_frame = FrameCounter;
448
449   return getAnimationFrame(graphic_info[graphic].anim_frames,
450                            graphic_info[graphic].anim_delay,
451                            graphic_info[graphic].anim_mode,
452                            graphic_info[graphic].anim_start_frame,
453                            sync_frame);
454 }
455
456 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
457                                     int graphic, int sync_frame, int mask_mode)
458 {
459   int frame = getGraphicAnimationFrame(graphic, sync_frame);
460
461   if (mask_mode == USE_MASKING)
462     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
463   else
464     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
465 }
466
467 inline void DrawGraphicAnimation(int x, int y, int graphic)
468 {
469   int lx = LEVELX(x), ly = LEVELY(y);
470
471   if (!IN_SCR_FIELD(x, y))
472     return;
473
474   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
475                           graphic, GfxFrame[lx][ly], NO_MASKING);
476   MarkTileDirty(x, y);
477 }
478
479 void DrawLevelGraphicAnimation(int x, int y, int graphic)
480 {
481   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
482 }
483
484 void DrawLevelElementAnimation(int x, int y, int element)
485 {
486   DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
487 }
488
489 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
490 {
491   int sx = SCREENX(x), sy = SCREENY(y);
492
493   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
494     return;
495
496   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
497     return;
498
499   DrawGraphicAnimation(sx, sy, graphic);
500 }
501
502 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
503 {
504   int sx = SCREENX(x), sy = SCREENY(y);
505   int graphic;
506
507   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
508     return;
509
510   graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
511
512   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
513     return;
514
515   DrawGraphicAnimation(sx, sy, graphic);
516 }
517
518 void DrawAllPlayers()
519 {
520   int i;
521
522   for(i=0; i<MAX_PLAYERS; i++)
523     if (stored_player[i].active)
524       DrawPlayer(&stored_player[i]);
525 }
526
527 void DrawPlayerField(int x, int y)
528 {
529   if (!IS_PLAYER(x, y))
530     return;
531
532   DrawPlayer(PLAYERINFO(x, y));
533 }
534
535 void DrawPlayer(struct PlayerInfo *player)
536 {
537   int jx = player->jx, jy = player->jy;
538   int last_jx = player->last_jx, last_jy = player->last_jy;
539   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
540   int sx = SCREENX(jx), sy = SCREENY(jy);
541   int sxx = 0, syy = 0;
542   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
543   int graphic;
544   int frame = 0;
545   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
546
547   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
548     return;
549
550 #if DEBUG
551   if (!IN_LEV_FIELD(jx,jy))
552   {
553     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
554     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
555     printf("DrawPlayerField(): This should never happen!\n");
556     return;
557   }
558 #endif
559
560   if (element == EL_EXPLOSION)
561     return;
562
563   /* draw things in the field the player is leaving, if needed */
564
565   if (player_is_moving)
566   {
567     if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
568     {
569       DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
570
571       if (last_element == EL_DYNAMITE_ACTIVE)
572         DrawDynamite(last_jx, last_jy);
573       else
574         DrawLevelFieldThruMask(last_jx, last_jy);
575     }
576     else if (last_element == EL_DYNAMITE_ACTIVE)
577       DrawDynamite(last_jx, last_jy);
578     else
579       DrawLevelField(last_jx, last_jy);
580
581     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
582     {
583       if (player->GfxPos)
584       {
585         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
586           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
587         else
588           DrawLevelElement(next_jx, next_jy, EL_EMPTY);
589       }
590       else
591         DrawLevelField(next_jx, next_jy);
592     }
593   }
594
595   if (!IN_SCR_FIELD(sx, sy))
596     return;
597
598   if (setup.direct_draw)
599     SetDrawtoField(DRAW_BUFFERED);
600
601   /* draw things behind the player, if needed */
602
603   if (Store[jx][jy])
604     DrawLevelElement(jx, jy, Store[jx][jy]);
605   else if (!IS_ACTIVE_BOMB(element))
606     DrawLevelField(jx, jy);
607   else
608     DrawLevelElement(jx, jy, EL_EMPTY);
609
610   /* draw player himself */
611
612   if (game.emulation == EMU_SUPAPLEX)
613   {
614     static int last_dir = MV_LEFT;
615     int action = (player->programmed_action ? player->programmed_action :
616                   player->action);
617     boolean action_moving =
618       (player_is_moving ||
619        ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
620         !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
621
622     graphic = IMG_SP_MURPHY;
623
624     if (player->Pushing)
625     {
626       if (player->MovDir == MV_LEFT)
627         graphic = IMG_SP_MURPHY_PUSHING_LEFT;
628       else if (player->MovDir == MV_RIGHT)
629         graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
630       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
631         graphic = IMG_SP_MURPHY_PUSHING_LEFT;
632       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
633         graphic = IMG_SP_MURPHY_PUSHING_RIGHT;
634     }
635     else if (player->snapped)
636     {
637       if (player->MovDir == MV_LEFT)
638         graphic = IMG_SP_MURPHY_SNAPPING_LEFT;
639       else if (player->MovDir == MV_RIGHT)
640         graphic = IMG_SP_MURPHY_SNAPPING_RIGHT;
641       else if (player->MovDir == MV_UP)
642         graphic = IMG_SP_MURPHY_SNAPPING_UP;
643       else if (player->MovDir == MV_DOWN)
644         graphic = IMG_SP_MURPHY_SNAPPING_DOWN;
645     }
646     else if (action_moving)
647     {
648       if (player->MovDir == MV_LEFT)
649         graphic = IMG_SP_MURPHY_MOVING_LEFT;
650       else if (player->MovDir == MV_RIGHT)
651         graphic = IMG_SP_MURPHY_MOVING_RIGHT;
652       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
653         graphic = IMG_SP_MURPHY_MOVING_LEFT;
654       else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
655         graphic = IMG_SP_MURPHY_MOVING_RIGHT;
656       else
657         graphic = IMG_SP_MURPHY_MOVING_LEFT;
658
659       frame = getGraphicAnimationFrame(graphic, -1);
660     }
661
662     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
663       last_dir = player->MovDir;
664   }
665   else
666   {
667     if (player->MovDir == MV_LEFT)
668       graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_LEFT :
669                  player->is_moving ? IMG_PLAYER1_MOVING_LEFT :
670                  IMG_PLAYER1_LEFT);
671     else if (player->MovDir == MV_RIGHT)
672       graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_RIGHT :
673                  player->is_moving ? IMG_PLAYER1_MOVING_RIGHT :
674                  IMG_PLAYER1_RIGHT);
675     else if (player->MovDir == MV_UP)
676       graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_UP :
677                  player->is_moving ? IMG_PLAYER1_MOVING_UP :
678                  IMG_PLAYER1_UP);
679     else        /* MV_DOWN || MV_NO_MOVING */
680       graphic = (player->Pushing ? IMG_PLAYER1_PUSHING_DOWN :
681                  player->is_moving ? IMG_PLAYER1_MOVING_DOWN :
682                  IMG_PLAYER1_DOWN);
683
684     graphic = PLAYER_NR_GFX(graphic, player->index_nr);
685
686 #if 0
687     frame = player->Frame;
688 #else
689     frame = getGraphicAnimationFrame(graphic, player->Frame);
690 #endif
691   }
692
693   if (player->GfxPos)
694   {
695     if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
696       sxx = player->GfxPos;
697     else
698       syy = player->GfxPos;
699   }
700
701   if (!setup.soft_scrolling && ScreenMovPos)
702     sxx = syy = 0;
703
704 #if 0
705   if (player->Frame)
706     printf("-> %d\n", player->Frame);
707 #endif
708
709   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
710
711   if (SHIELD_ON(player))
712   {
713     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
714                    IMG_SHIELD_NORMAL_ACTIVE);
715     int frame = getGraphicAnimationFrame(graphic, -1);
716
717     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
718   }
719
720 #if 0
721   if (player->Pushing && player->GfxPos)
722 #else
723   if (player->Pushing && player_is_moving)
724 #endif
725   {
726     int px = SCREENX(next_jx), py = SCREENY(next_jy);
727
728     if ((sxx || syy) &&
729         (element == EL_SOKOBAN_FIELD_EMPTY ||
730          Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
731       DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
732                                  NO_CUTTING);
733     else
734     {
735       int element = Feld[next_jx][next_jy];
736       int graphic = el2img(element);
737 #if 1
738       int frame = 0;
739 #endif
740
741       if ((sxx || syy) && IS_PUSHABLE(element))
742       {
743         graphic = el_act_dir2img(element, ACTION_MOVING, player->MovDir);
744 #if 1
745         frame = getGraphicAnimationFrame(graphic, player->GfxPos);
746
747         frame = getGraphicAnimationFrame(graphic, player->Frame);
748 #endif
749
750 #if 0
751         printf("-> %d [%d]\n", player->Frame, player->GfxPos);
752 #endif
753
754 #if 0
755         /* !!! FIX !!! */
756         if (player->MovDir == MV_LEFT)
757           frame = 3 - frame;
758 #endif
759
760 #if 0
761         frame = (player->GfxPos / (TILEX / 4));
762
763         if (player->MovDir == MV_RIGHT)
764           frame = (frame + 4) % 4;
765 #endif
766       }
767
768       DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
769                          NO_CUTTING, NO_MASKING);
770     }
771   }
772
773   /* draw things in front of player (active dynamite or dynabombs) */
774
775   if (IS_ACTIVE_BOMB(element))
776   {
777     graphic = el2img(element);
778
779 #if 0
780     if (element == EL_DYNAMITE_ACTIVE)
781     {
782       if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
783         frame = 6;
784     }
785     else
786     {
787       if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
788         frame = 7 - frame;
789     }
790 #else
791
792 #if 0
793     frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
794 #else
795     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
796 #endif
797
798 #endif
799
800     if (game.emulation == EMU_SUPAPLEX)
801       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
802     else
803       DrawGraphicThruMask(sx, sy, graphic, frame);
804   }
805
806   if (player_is_moving && last_element == EL_EXPLOSION)
807   {
808     int stored = Store[last_jx][last_jy];
809     int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
810                    stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
811                    IMG_SP_EXPLOSION);
812     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
813     int phase = ExplodePhase[last_jx][last_jy] - 1;
814     int frame = getGraphicAnimationFrame(graphic, phase - delay);
815
816     if (phase >= delay)
817       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
818   }
819
820   /* draw elements that stay over the player */
821   /* handle the field the player is leaving ... */
822   if (player_is_moving && IS_OVER_PLAYER(last_element))
823     DrawLevelField(last_jx, last_jy);
824
825   /* ... and the field the player is entering */
826   if (IS_OVER_PLAYER(element))
827     DrawLevelField(jx, jy);
828
829   if (setup.direct_draw)
830   {
831     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
832     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
833     int x_size = TILEX * (1 + ABS(jx - last_jx));
834     int y_size = TILEY * (1 + ABS(jy - last_jy));
835
836     BlitBitmap(drawto_field, window,
837                dest_x, dest_y, x_size, y_size, dest_x, dest_y);
838     SetDrawtoField(DRAW_DIRECT);
839   }
840
841   MarkTileDirty(sx,sy);
842 }
843
844 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
845 {
846   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
847   int offset_x = graphic_info[graphic].offset_x;
848   int offset_y = graphic_info[graphic].offset_y;
849   int src_x = graphic_info[graphic].src_x + frame * offset_x;
850   int src_y = graphic_info[graphic].src_y + frame * offset_y;
851
852   *bitmap = src_bitmap;
853   *x = src_x;
854   *y = src_y;
855 }
856
857 void DrawGraphic(int x, int y, int graphic, int frame)
858 {
859 #if DEBUG
860   if (!IN_SCR_FIELD(x, y))
861   {
862     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
863     printf("DrawGraphic(): This should never happen!\n");
864     return;
865   }
866 #endif
867
868   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
869   MarkTileDirty(x, y);
870 }
871
872 #if 0
873 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
874 {
875   Bitmap *src_bitmap;
876   int src_x, src_y;
877
878   getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
879   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
880 }
881 #endif
882
883 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
884                     int frame)
885 {
886 #if 1
887   Bitmap *src_bitmap;
888   int src_x, src_y;
889
890   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
891 #else
892   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
893   int src_x = graphic_info[graphic].src_x;
894   int src_y = graphic_info[graphic].src_y;
895   int offset_x = graphic_info[graphic].offset_x;
896   int offset_y = graphic_info[graphic].offset_y;
897
898   src_x += frame * offset_x;
899   src_y += frame * offset_y;
900 #endif
901
902   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
903 }
904
905 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
906 {
907 #if DEBUG
908   if (!IN_SCR_FIELD(x, y))
909   {
910     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
911     printf("DrawGraphicThruMask(): This should never happen!\n");
912     return;
913   }
914 #endif
915
916   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
917                          frame);
918   MarkTileDirty(x, y);
919 }
920
921 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
922                             int frame)
923 {
924 #if 1
925   Bitmap *src_bitmap;
926   int src_x, src_y;
927   GC drawing_gc;
928
929   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
930   drawing_gc = src_bitmap->stored_clip_gc;
931 #else
932   GC drawing_gc = src_bitmap->stored_clip_gc;
933   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
934   int src_x = graphic_info[graphic].src_x;
935   int src_y = graphic_info[graphic].src_y;
936   int offset_x = graphic_info[graphic].offset_x;
937   int offset_y = graphic_info[graphic].offset_y;
938
939   src_x += frame * offset_x;
940   src_y += frame * offset_y;
941
942 #endif
943
944   SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
945   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
946 }
947
948 void DrawMiniGraphic(int x, int y, int graphic)
949 {
950   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
951   MarkTileDirty(x / 2, y / 2);
952 }
953
954 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
955 {
956   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
957   int mini_startx = 0;
958   int mini_starty = src_bitmap->height * 2 / 3;
959   int src_x = mini_startx + graphic_info[graphic].src_x / 2;
960   int src_y = mini_starty + graphic_info[graphic].src_y / 2;
961
962   if (src_x + MINI_TILEX > src_bitmap->width ||
963       src_y + MINI_TILEY > src_bitmap->height)
964   {
965     /* graphic of desired size seems not to be contained in this image;
966        dirty workaround: get it from the middle of the normal sized image */
967
968     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
969     src_x += (TILEX / 2 - MINI_TILEX / 2);
970     src_y += (TILEY / 2 - MINI_TILEY / 2);
971   }
972
973   *bitmap = src_bitmap;
974   *x = src_x;
975   *y = src_y;
976 }
977
978 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
979 {
980   Bitmap *src_bitmap;
981   int src_x, src_y;
982
983   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
984   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
985 }
986
987 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
988                         int cut_mode, int mask_mode)
989 {
990   Bitmap *src_bitmap;
991   GC drawing_gc;
992   int src_x;
993   int src_y;
994   int offset_x;
995   int offset_y;
996
997   int width = TILEX, height = TILEY;
998   int cx = 0, cy = 0;
999   int dest_x, dest_y;
1000
1001   if (graphic < 0)
1002   {
1003     DrawGraphic(x, y, graphic, frame);
1004     return;
1005   }
1006
1007   if (dx || dy)                 /* shifted graphic */
1008   {
1009     if (x < BX1)                /* object enters playfield from the left */
1010     {
1011       x = BX1;
1012       width = dx;
1013       cx = TILEX - dx;
1014       dx = 0;
1015     }
1016     else if (x > BX2)           /* object enters playfield from the right */
1017     {
1018       x = BX2;
1019       width = -dx;
1020       dx = TILEX + dx;
1021     }
1022     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1023     {
1024       width += dx;
1025       cx = -dx;
1026       dx = 0;
1027     }
1028     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1029       width -= dx;
1030     else if (dx)                /* general horizontal movement */
1031       MarkTileDirty(x + SIGN(dx), y);
1032
1033     if (y < BY1)                /* object enters playfield from the top */
1034     {
1035       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1036         return;
1037
1038       y = BY1;
1039       height = dy;
1040       cy = TILEY - dy;
1041       dy = 0;
1042     }
1043     else if (y > BY2)           /* object enters playfield from the bottom */
1044     {
1045       y = BY2;
1046       height = -dy;
1047       dy = TILEY + dy;
1048     }
1049     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1050     {
1051       height += dy;
1052       cy = -dy;
1053       dy = 0;
1054     }
1055     else if (dy > 0 && cut_mode == CUT_ABOVE)
1056     {
1057       if (y == BY2)             /* object completely above bottom border */
1058         return;
1059
1060       height = dy;
1061       cy = TILEY - dy;
1062       dy = TILEY;
1063       MarkTileDirty(x, y + 1);
1064     }                           /* object leaves playfield to the bottom */
1065     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1066       height -= dy;
1067     else if (dy)                /* general vertical movement */
1068       MarkTileDirty(x, y + SIGN(dy));
1069   }
1070
1071   src_bitmap = graphic_info[graphic].bitmap;
1072   src_x = graphic_info[graphic].src_x;
1073   src_y = graphic_info[graphic].src_y;
1074   offset_x = graphic_info[graphic].offset_x;
1075   offset_y = graphic_info[graphic].offset_y;
1076
1077   drawing_gc = src_bitmap->stored_clip_gc;
1078
1079   src_x += frame * offset_x;
1080   src_y += frame * offset_y;
1081
1082   src_x += cx;
1083   src_y += cy;
1084
1085   dest_x = FX + x * TILEX + dx;
1086   dest_y = FY + y * TILEY + dy;
1087
1088 #if DEBUG
1089   if (!IN_SCR_FIELD(x,y))
1090   {
1091     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1092     printf("DrawGraphicShifted(): This should never happen!\n");
1093     return;
1094   }
1095 #endif
1096
1097   if (mask_mode == USE_MASKING)
1098   {
1099     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1100     BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1101                      dest_x, dest_y);
1102   }
1103   else
1104     BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1105                dest_x, dest_y);
1106
1107   MarkTileDirty(x,y);
1108 }
1109
1110 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1111                                 int frame, int cut_mode)
1112 {
1113   DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1114 }
1115
1116 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1117                           int cut_mode, int mask_mode)
1118 {
1119   int lx = LEVELX(x), ly = LEVELY(y);
1120   int graphic;
1121   int frame;
1122
1123   if (IN_LEV_FIELD(lx, ly))
1124   {
1125     SetRandomAnimationValue(lx, ly);
1126
1127     graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1128     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1129   }
1130   else  /* border element */
1131   {
1132     graphic = el2img(element);
1133     frame = getGraphicAnimationFrame(graphic, -1);
1134   }
1135
1136   if (element == EL_WALL_GROWING)
1137   {
1138     boolean left_stopped = FALSE, right_stopped = FALSE;
1139
1140     if (!IN_LEV_FIELD(lx - 1, ly) || IS_MAUER(Feld[lx - 1][ly]))
1141       left_stopped = TRUE;
1142     if (!IN_LEV_FIELD(lx + 1, ly) || IS_MAUER(Feld[lx + 1][ly]))
1143       right_stopped = TRUE;
1144
1145     if (left_stopped && right_stopped)
1146       graphic = IMG_WALL;
1147     else if (left_stopped)
1148     {
1149       graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1150       frame = graphic_info[graphic].anim_frames - 1;
1151     }
1152     else if (right_stopped)
1153     {
1154       graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1155       frame = graphic_info[graphic].anim_frames - 1;
1156     }
1157   }
1158   else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1159   {
1160     graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1161                element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1162                element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1163                element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1164                IMG_AMOEBA_DEAD_PART1);
1165
1166     graphic += (x + 2 * y + 4) % 4;
1167   }
1168
1169   if (dx || dy)
1170     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1171   else if (mask_mode == USE_MASKING)
1172     DrawGraphicThruMask(x, y, graphic, frame);
1173   else
1174     DrawGraphic(x, y, graphic, frame);
1175 }
1176
1177 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1178                          int cut_mode, int mask_mode)
1179 {
1180   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1181     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1182                          cut_mode, mask_mode);
1183 }
1184
1185 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1186                               int cut_mode)
1187 {
1188   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1189 }
1190
1191 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1192                              int cut_mode)
1193 {
1194   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1195 }
1196
1197 #if 0
1198 void DrawOldScreenElementThruMask(int x, int y, int element)
1199 {
1200   DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1201 }
1202
1203 void DrawScreenElementThruMask(int x, int y, int element)
1204 {
1205   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1206 }
1207 #endif
1208
1209 void DrawLevelElementThruMask(int x, int y, int element)
1210 {
1211   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1212 }
1213
1214 void DrawLevelFieldThruMask(int x, int y)
1215 {
1216   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1217 }
1218
1219 void DrawCrumbledSand(int x, int y)
1220 {
1221   Bitmap *src_bitmap;
1222   int src_x, src_y;
1223   int i, width, height, cx,cy;
1224   int lx = LEVELX(x), ly = LEVELY(y);
1225   int element, graphic;
1226   int snip = 4;
1227   static int xy[4][2] =
1228   {
1229     { 0, -1 },
1230     { -1, 0 },
1231     { +1, 0 },
1232     { 0, +1 }
1233   };
1234
1235   if (!IN_LEV_FIELD(lx, ly))
1236     return;
1237
1238   element = Feld[lx][ly];
1239
1240   if (element == EL_SAND ||
1241       element == EL_LANDMINE ||
1242       element == EL_TRAP ||
1243       element == EL_TRAP_ACTIVE)
1244   {
1245     if (!IN_SCR_FIELD(x, y))
1246       return;
1247
1248     graphic = IMG_SAND_CRUMBLED;
1249
1250     src_bitmap = graphic_info[graphic].bitmap;
1251     src_x = graphic_info[graphic].src_x;
1252     src_y = graphic_info[graphic].src_y;
1253
1254     for(i=0; i<4; i++)
1255     {
1256       int lxx, lyy;
1257
1258       lxx = lx + xy[i][0];
1259       lyy = ly + xy[i][1];
1260       if (!IN_LEV_FIELD(lxx, lyy))
1261         element = EL_STEELWALL;
1262       else
1263         element = Feld[lxx][lyy];
1264
1265       if (element == EL_SAND ||
1266           element == EL_LANDMINE ||
1267           element == EL_TRAP ||
1268           element == EL_TRAP_ACTIVE)
1269         continue;
1270
1271       if (i == 1 || i == 2)
1272       {
1273         width = snip;
1274         height = TILEY;
1275         cx = (i == 2 ? TILEX - snip : 0);
1276         cy = 0;
1277       }
1278       else
1279       {
1280         width = TILEX;
1281         height = snip;
1282         cx = 0;
1283         cy = (i == 3 ? TILEY - snip : 0);
1284       }
1285
1286       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1287                  width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1288     }
1289
1290     MarkTileDirty(x, y);
1291   }
1292   else
1293   {
1294     graphic = IMG_SAND_CRUMBLED;
1295
1296     src_bitmap = graphic_info[graphic].bitmap;
1297     src_x = graphic_info[graphic].src_x;
1298     src_y = graphic_info[graphic].src_y;
1299
1300     for(i=0; i<4; i++)
1301     {
1302       int xx, yy, lxx, lyy;
1303
1304       xx = x + xy[i][0];
1305       yy = y + xy[i][1];
1306       lxx = lx + xy[i][0];
1307       lyy = ly + xy[i][1];
1308
1309       if (!IN_LEV_FIELD(lxx, lyy) ||
1310           (Feld[lxx][lyy] != EL_SAND &&
1311            Feld[lxx][lyy] != EL_LANDMINE &&
1312            Feld[lxx][lyy] != EL_TRAP &&
1313            Feld[lxx][lyy] != EL_TRAP_ACTIVE) ||
1314           !IN_SCR_FIELD(xx, yy))
1315         continue;
1316
1317       if (i == 1 || i == 2)
1318       {
1319         width = snip;
1320         height = TILEY;
1321         cx = (i == 1 ? TILEX - snip : 0);
1322         cy = 0;
1323       }
1324       else
1325       {
1326         width = TILEX;
1327         height = snip;
1328         cx = 0;
1329         cy = (i==0 ? TILEY-snip : 0);
1330       }
1331
1332       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1333                  width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1334
1335       MarkTileDirty(xx, yy);
1336     }
1337   }
1338 }
1339
1340 void DrawScreenElement(int x, int y, int element)
1341 {
1342   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1343   DrawCrumbledSand(x, y);
1344 }
1345
1346 void DrawLevelElement(int x, int y, int element)
1347 {
1348   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1349     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1350 }
1351
1352 void DrawScreenField(int x, int y)
1353 {
1354   int lx = LEVELX(x), ly = LEVELY(y);
1355   int element, content;
1356
1357   if (!IN_LEV_FIELD(lx, ly))
1358   {
1359     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1360       element = EL_EMPTY;
1361     else
1362       element = BorderElement;
1363
1364     DrawScreenElement(x, y, element);
1365     return;
1366   }
1367
1368   element = Feld[lx][ly];
1369   content = Store[lx][ly];
1370
1371   if (IS_MOVING(lx, ly))
1372   {
1373     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1374     boolean cut_mode = NO_CUTTING;
1375
1376     if (element == EL_QUICKSAND_EMPTYING ||
1377         element == EL_MAGIC_WALL_EMPTYING ||
1378         element == EL_BD_MAGIC_WALL_EMPTYING ||
1379         element == EL_AMOEBA_DRIPPING)
1380       cut_mode = CUT_ABOVE;
1381     else if (element == EL_QUICKSAND_FILLING ||
1382              element == EL_MAGIC_WALL_FILLING ||
1383              element == EL_BD_MAGIC_WALL_FILLING)
1384       cut_mode = CUT_BELOW;
1385
1386     if (cut_mode == CUT_ABOVE)
1387       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1388     else
1389       DrawScreenElement(x, y, EL_EMPTY);
1390
1391     if (horiz_move)
1392       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1393     else if (cut_mode == NO_CUTTING)
1394       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1395     else
1396       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1397
1398     if (content == EL_ACID)
1399       DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1400   }
1401   else if (IS_BLOCKED(lx, ly))
1402   {
1403     int oldx, oldy;
1404     int sx, sy;
1405     int horiz_move;
1406     boolean cut_mode = NO_CUTTING;
1407     int element_old, content_old;
1408
1409     Blocked2Moving(lx, ly, &oldx, &oldy);
1410     sx = SCREENX(oldx);
1411     sy = SCREENY(oldy);
1412     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1413                   MovDir[oldx][oldy] == MV_RIGHT);
1414
1415     element_old = Feld[oldx][oldy];
1416     content_old = Store[oldx][oldy];
1417
1418     if (element_old == EL_QUICKSAND_EMPTYING ||
1419         element_old == EL_MAGIC_WALL_EMPTYING ||
1420         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1421         element_old == EL_AMOEBA_DRIPPING)
1422       cut_mode = CUT_ABOVE;
1423
1424     DrawScreenElement(x, y, EL_EMPTY);
1425
1426     if (horiz_move)
1427       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1428                                NO_CUTTING);
1429     else if (cut_mode == NO_CUTTING)
1430       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1431                                cut_mode);
1432     else
1433       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1434                                cut_mode);
1435   }
1436   else if (IS_DRAWABLE(element))
1437     DrawScreenElement(x, y, element);
1438   else
1439     DrawScreenElement(x, y, EL_EMPTY);
1440 }
1441
1442 void DrawLevelField(int x, int y)
1443 {
1444   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1445     DrawScreenField(SCREENX(x), SCREENY(y));
1446   else if (IS_MOVING(x, y))
1447   {
1448     int newx,newy;
1449
1450     Moving2Blocked(x, y, &newx, &newy);
1451     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1452       DrawScreenField(SCREENX(newx), SCREENY(newy));
1453   }
1454   else if (IS_BLOCKED(x, y))
1455   {
1456     int oldx, oldy;
1457
1458     Blocked2Moving(x, y, &oldx, &oldy);
1459     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1460       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1461   }
1462 }
1463
1464 void DrawMiniElement(int x, int y, int element)
1465 {
1466   int graphic;
1467
1468   graphic = el2edimg(element);
1469   DrawMiniGraphic(x, y, graphic);
1470 }
1471
1472 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1473 {
1474   int x = sx + scroll_x, y = sy + scroll_y;
1475
1476   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1477     DrawMiniElement(sx, sy, EL_EMPTY);
1478   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1479     DrawMiniElement(sx, sy, Feld[x][y]);
1480   else
1481   {
1482     int steel_type, steel_position;
1483     int border[6][2] =
1484     {
1485       { IMG_STEELWALL_TOPLEFT,          IMG_INVISIBLE_STEELWALL_TOPLEFT     },
1486       { IMG_STEELWALL_TOPRIGHT,         IMG_INVISIBLE_STEELWALL_TOPRIGHT    },
1487       { IMG_STEELWALL_BOTTOMLEFT,       IMG_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1488       { IMG_STEELWALL_BOTTOMRIGHT,      IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1489       { IMG_STEELWALL_VERTICAL,         IMG_INVISIBLE_STEELWALL_VERTICAL    },
1490       { IMG_STEELWALL_HORIZONTAL,       IMG_INVISIBLE_STEELWALL_HORIZONTAL  }
1491     };
1492
1493     steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1494     steel_position = (x == -1 && y == -1                        ? 0 :
1495                       x == lev_fieldx && y == -1                ? 1 :
1496                       x == -1 && y == lev_fieldy                ? 2 :
1497                       x == lev_fieldx && y == lev_fieldy        ? 3 :
1498                       x == -1 || x == lev_fieldx                ? 4 :
1499                       y == -1 || y == lev_fieldy                ? 5 : -1);
1500
1501     if (steel_position != -1)
1502       DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1503   }
1504 }
1505
1506 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1507 {
1508   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1509   int mini_startx = src_bitmap->width * 3 / 4;
1510   int mini_starty = src_bitmap->height * 2 / 3;
1511   int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1512   int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1513
1514   if (src_x + MICRO_TILEX > src_bitmap->width ||
1515       src_y + MICRO_TILEY > src_bitmap->height)
1516   {
1517     /* graphic of desired size seems not to be contained in this image;
1518        dirty workaround: get it from the middle of the normal sized image */
1519
1520     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1521     src_x += (TILEX / 2 - MICRO_TILEX / 2);
1522     src_y += (TILEY / 2 - MICRO_TILEY / 2);
1523   }
1524
1525   *bitmap = src_bitmap;
1526   *x = src_x;
1527   *y = src_y;
1528 }
1529
1530 void DrawMicroElement(int xpos, int ypos, int element)
1531 {
1532   Bitmap *src_bitmap;
1533   int src_x, src_y;
1534   int graphic = el2img(element);
1535
1536   getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1537   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1538              xpos, ypos);
1539 }
1540
1541 void DrawLevel()
1542 {
1543   int x,y;
1544
1545   SetDrawBackgroundMask(REDRAW_NONE);
1546   ClearWindow();
1547
1548   for(x=BX1; x<=BX2; x++)
1549     for(y=BY1; y<=BY2; y++)
1550       DrawScreenField(x, y);
1551
1552   redraw_mask |= REDRAW_FIELD;
1553 }
1554
1555 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1556 {
1557   int x,y;
1558
1559   for(x=0; x<size_x; x++)
1560     for(y=0; y<size_y; y++)
1561       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1562
1563   redraw_mask |= REDRAW_FIELD;
1564 }
1565
1566 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1567 {
1568   int x, y;
1569
1570   DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1571
1572   if (lev_fieldx < STD_LEV_FIELDX)
1573     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1574   if (lev_fieldy < STD_LEV_FIELDY)
1575     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1576
1577   xpos += MICRO_TILEX;
1578   ypos += MICRO_TILEY;
1579
1580   for(x=-1; x<=STD_LEV_FIELDX; x++)
1581   {
1582     for(y=-1; y<=STD_LEV_FIELDY; y++)
1583     {
1584       int lx = from_x + x, ly = from_y + y;
1585
1586       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1587         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1588                          Ur[lx][ly]);
1589       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1590                && BorderElement != EL_EMPTY)
1591         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1592                          BorderElement);
1593     }
1594   }
1595
1596   redraw_mask |= REDRAW_MICROLEVEL;
1597 }
1598
1599 #define MICROLABEL_EMPTY                0
1600 #define MICROLABEL_LEVEL_NAME           1
1601 #define MICROLABEL_CREATED_BY           2
1602 #define MICROLABEL_LEVEL_AUTHOR         3
1603 #define MICROLABEL_IMPORTED_FROM        4
1604 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1605
1606 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1607
1608 static void DrawMicroLevelLabelExt(int mode)
1609 {
1610   char label_text[MAX_MICROLABEL_SIZE + 1];
1611
1612   DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1613
1614   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1615                        mode == MICROLABEL_CREATED_BY ? "created by" :
1616                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1617                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1618                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1619                        leveldir_current->imported_from : ""),
1620           MAX_MICROLABEL_SIZE);
1621   label_text[MAX_MICROLABEL_SIZE] = '\0';
1622
1623   if (strlen(label_text) > 0)
1624   {
1625     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1626     int lypos = MICROLABEL_YPOS;
1627
1628     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1629   }
1630
1631   redraw_mask |= REDRAW_MICROLEVEL;
1632 }
1633
1634 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1635 {
1636   static unsigned long scroll_delay = 0;
1637   static unsigned long label_delay = 0;
1638   static int from_x, from_y, scroll_direction;
1639   static int label_state, label_counter;
1640
1641   if (restart)
1642   {
1643     from_x = from_y = 0;
1644     scroll_direction = MV_RIGHT;
1645     label_state = 1;
1646     label_counter = 0;
1647
1648     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1649     DrawMicroLevelLabelExt(label_state);
1650
1651     /* initialize delay counters */
1652     DelayReached(&scroll_delay, 0);
1653     DelayReached(&label_delay, 0);
1654
1655     return;
1656   }
1657
1658   /* scroll micro level, if needed */
1659   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1660       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1661   {
1662     switch (scroll_direction)
1663     {
1664       case MV_LEFT:
1665         if (from_x > 0)
1666           from_x--;
1667         else
1668           scroll_direction = MV_UP;
1669         break;
1670
1671       case MV_RIGHT:
1672         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1673           from_x++;
1674         else
1675           scroll_direction = MV_DOWN;
1676         break;
1677
1678       case MV_UP:
1679         if (from_y > 0)
1680           from_y--;
1681         else
1682           scroll_direction = MV_RIGHT;
1683         break;
1684
1685       case MV_DOWN:
1686         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1687           from_y++;
1688         else
1689           scroll_direction = MV_LEFT;
1690         break;
1691
1692       default:
1693         break;
1694     }
1695
1696     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1697   }
1698
1699   /* redraw micro level label, if needed */
1700   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1701       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1702       strcmp(level.author, leveldir_current->name) != 0 &&
1703       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1704   {
1705     int max_label_counter = 23;
1706
1707     if (leveldir_current->imported_from != NULL)
1708       max_label_counter += 14;
1709
1710     label_counter = (label_counter + 1) % max_label_counter;
1711     label_state = (label_counter >= 0 && label_counter <= 7 ?
1712                    MICROLABEL_LEVEL_NAME :
1713                    label_counter >= 9 && label_counter <= 12 ?
1714                    MICROLABEL_CREATED_BY :
1715                    label_counter >= 14 && label_counter <= 21 ?
1716                    MICROLABEL_LEVEL_AUTHOR :
1717                    label_counter >= 23 && label_counter <= 26 ?
1718                    MICROLABEL_IMPORTED_FROM :
1719                    label_counter >= 28 && label_counter <= 35 ?
1720                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1721     DrawMicroLevelLabelExt(label_state);
1722   }
1723 }
1724
1725 int REQ_in_range(int x, int y)
1726 {
1727   if (y > DY+249 && y < DY+278)
1728   {
1729     if (x > DX+1 && x < DX+48)
1730       return 1;
1731     else if (x > DX+51 && x < DX+98) 
1732       return 2;
1733   }
1734   return 0;
1735 }
1736
1737 #define MAX_REQUEST_LINES               13
1738 #define MAX_REQUEST_LINE_LEN            7
1739
1740 boolean Request(char *text, unsigned int req_state)
1741 {
1742   int mx, my, ty, result = -1;
1743   unsigned int old_door_state;
1744
1745 #if defined(PLATFORM_UNIX)
1746   /* pause network game while waiting for request to answer */
1747   if (options.network &&
1748       game_status == PLAYING &&
1749       req_state & REQUEST_WAIT_FOR)
1750     SendToServer_PausePlaying();
1751 #endif
1752
1753   old_door_state = GetDoorState();
1754
1755   UnmapAllGadgets();
1756
1757   CloseDoor(DOOR_CLOSE_1);
1758
1759   /* save old door content */
1760   BlitBitmap(bitmap_db_door, bitmap_db_door,
1761              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1762              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1763
1764   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1765
1766   /* clear door drawing field */
1767   DrawBackground(DX, DY, DXSIZE, DYSIZE);
1768
1769   /* write text for request */
1770   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1771   {
1772     char text_line[MAX_REQUEST_LINE_LEN + 1];
1773     int tx, tl, tc;
1774
1775     if (!*text)
1776       break;
1777
1778     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1779     {
1780       tc = *(text + tx);
1781       if (!tc || tc == ' ')
1782         break;
1783     }
1784
1785     if (!tl)
1786     { 
1787       text++; 
1788       ty--; 
1789       continue; 
1790     }
1791
1792     strncpy(text_line, text, tl);
1793     text_line[tl] = 0;
1794
1795     DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1796              text_line, FS_SMALL, FC_YELLOW);
1797
1798     text += tl + (tc == ' ' ? 1 : 0);
1799   }
1800
1801   if (req_state & REQ_ASK)
1802   {
1803     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1804     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1805   }
1806   else if (req_state & REQ_CONFIRM)
1807   {
1808     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1809   }
1810   else if (req_state & REQ_PLAYER)
1811   {
1812     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1813     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1814     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1815     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1816   }
1817
1818   /* copy request gadgets to door backbuffer */
1819   BlitBitmap(drawto, bitmap_db_door,
1820              DX, DY, DXSIZE, DYSIZE,
1821              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1822
1823   OpenDoor(DOOR_OPEN_1);
1824
1825 #if 0
1826   ClearEventQueue();
1827 #endif
1828
1829   if (!(req_state & REQUEST_WAIT_FOR))
1830   {
1831     SetDrawBackgroundMask(REDRAW_FIELD);
1832
1833     return FALSE;
1834   }
1835
1836   if (game_status != MAINMENU)
1837     InitAnimation();
1838
1839   button_status = MB_RELEASED;
1840
1841   request_gadget_id = -1;
1842
1843   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1844
1845   while(result < 0)
1846   {
1847     if (PendingEvent())
1848     {
1849       Event event;
1850
1851       NextEvent(&event);
1852
1853       switch(event.type)
1854       {
1855         case EVENT_BUTTONPRESS:
1856         case EVENT_BUTTONRELEASE:
1857         case EVENT_MOTIONNOTIFY:
1858         {
1859           if (event.type == EVENT_MOTIONNOTIFY)
1860           {
1861             if (!PointerInWindow(window))
1862               continue; /* window and pointer are on different screens */
1863
1864             if (!button_status)
1865               continue;
1866
1867             motion_status = TRUE;
1868             mx = ((MotionEvent *) &event)->x;
1869             my = ((MotionEvent *) &event)->y;
1870           }
1871           else
1872           {
1873             motion_status = FALSE;
1874             mx = ((ButtonEvent *) &event)->x;
1875             my = ((ButtonEvent *) &event)->y;
1876             if (event.type == EVENT_BUTTONPRESS)
1877               button_status = ((ButtonEvent *) &event)->button;
1878             else
1879               button_status = MB_RELEASED;
1880           }
1881
1882           /* this sets 'request_gadget_id' */
1883           HandleGadgets(mx, my, button_status);
1884
1885           switch(request_gadget_id)
1886           {
1887             case TOOL_CTRL_ID_YES:
1888               result = TRUE;
1889               break;
1890             case TOOL_CTRL_ID_NO:
1891               result = FALSE;
1892               break;
1893             case TOOL_CTRL_ID_CONFIRM:
1894               result = TRUE | FALSE;
1895               break;
1896
1897             case TOOL_CTRL_ID_PLAYER_1:
1898               result = 1;
1899               break;
1900             case TOOL_CTRL_ID_PLAYER_2:
1901               result = 2;
1902               break;
1903             case TOOL_CTRL_ID_PLAYER_3:
1904               result = 3;
1905               break;
1906             case TOOL_CTRL_ID_PLAYER_4:
1907               result = 4;
1908               break;
1909
1910             default:
1911               break;
1912           }
1913
1914           break;
1915         }
1916
1917         case EVENT_KEYPRESS:
1918           switch(GetEventKey((KeyEvent *)&event, TRUE))
1919           {
1920             case KSYM_Return:
1921               result = 1;
1922               break;
1923
1924             case KSYM_Escape:
1925               result = 0;
1926               break;
1927
1928             default:
1929               break;
1930           }
1931           if (req_state & REQ_PLAYER)
1932             result = 0;
1933           break;
1934
1935         case EVENT_KEYRELEASE:
1936           ClearPlayerAction();
1937           break;
1938
1939         default:
1940           HandleOtherEvents(&event);
1941           break;
1942       }
1943     }
1944     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1945     {
1946       int joy = AnyJoystick();
1947
1948       if (joy & JOY_BUTTON_1)
1949         result = 1;
1950       else if (joy & JOY_BUTTON_2)
1951         result = 0;
1952     }
1953
1954     DoAnimation();
1955
1956     /* don't eat all CPU time */
1957     Delay(10);
1958   }
1959
1960   if (game_status != MAINMENU)
1961     StopAnimation();
1962
1963   UnmapToolButtons();
1964
1965   if (!(req_state & REQ_STAY_OPEN))
1966   {
1967     CloseDoor(DOOR_CLOSE_1);
1968
1969     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1970     {
1971       BlitBitmap(bitmap_db_door, bitmap_db_door,
1972                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1973                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1974       OpenDoor(DOOR_OPEN_1);
1975     }
1976   }
1977
1978   RemapAllGadgets();
1979
1980   SetDrawBackgroundMask(REDRAW_FIELD);
1981
1982 #if defined(PLATFORM_UNIX)
1983   /* continue network game after request */
1984   if (options.network &&
1985       game_status == PLAYING &&
1986       req_state & REQUEST_WAIT_FOR)
1987     SendToServer_ContinuePlaying();
1988 #endif
1989
1990   return result;
1991 }
1992
1993 unsigned int OpenDoor(unsigned int door_state)
1994 {
1995   unsigned int new_door_state;
1996
1997   if (door_state & DOOR_COPY_BACK)
1998   {
1999     BlitBitmap(bitmap_db_door, bitmap_db_door,
2000                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2001                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2002     door_state &= ~DOOR_COPY_BACK;
2003   }
2004
2005   new_door_state = MoveDoor(door_state);
2006
2007   return(new_door_state);
2008 }
2009
2010 unsigned int CloseDoor(unsigned int door_state)
2011 {
2012   unsigned int new_door_state;
2013
2014   BlitBitmap(backbuffer, bitmap_db_door,
2015              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2016   BlitBitmap(backbuffer, bitmap_db_door,
2017              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2018
2019   new_door_state = MoveDoor(door_state);
2020
2021   return(new_door_state);
2022 }
2023
2024 unsigned int GetDoorState()
2025 {
2026   return MoveDoor(DOOR_GET_STATE);
2027 }
2028
2029 unsigned int SetDoorState(unsigned int door_state)
2030 {
2031   return MoveDoor(door_state | DOOR_SET_STATE);
2032 }
2033
2034 unsigned int MoveDoor(unsigned int door_state)
2035 {
2036   static int door1 = DOOR_OPEN_1;
2037   static int door2 = DOOR_CLOSE_2;
2038   static unsigned long door_delay = 0;
2039   int x, start, stepsize = 2;
2040   unsigned long door_delay_value = stepsize * 5;
2041
2042   if (door_state == DOOR_GET_STATE)
2043     return(door1 | door2);
2044
2045   if (door_state & DOOR_SET_STATE)
2046   {
2047     if (door_state & DOOR_ACTION_1)
2048       door1 = door_state & DOOR_ACTION_1;
2049     if (door_state & DOOR_ACTION_2)
2050       door2 = door_state & DOOR_ACTION_2;
2051
2052     return(door1 | door2);
2053   }
2054
2055   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2056     door_state &= ~DOOR_OPEN_1;
2057   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2058     door_state &= ~DOOR_CLOSE_1;
2059   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2060     door_state &= ~DOOR_OPEN_2;
2061   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2062     door_state &= ~DOOR_CLOSE_2;
2063
2064   if (setup.quick_doors)
2065   {
2066     stepsize = 20;
2067     door_delay_value = 0;
2068
2069     StopSound(SND_MENU_DOOR_OPENING);
2070     StopSound(SND_MENU_DOOR_CLOSING);
2071   }
2072
2073   if (global.autoplay_leveldir)
2074   {
2075     door_state |= DOOR_NO_DELAY;
2076     door_state &= ~DOOR_CLOSE_ALL;
2077   }
2078
2079   if (door_state & DOOR_ACTION)
2080   {
2081     if (!(door_state & DOOR_NO_DELAY))
2082     {
2083       /* opening door sound has priority over simultaneously closing door */
2084       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2085         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2086       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2087         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2088     }
2089
2090     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2091
2092     for(x=start; x<=DXSIZE; x+=stepsize)
2093     {
2094       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2095       GC gc = bitmap->stored_clip_gc;
2096
2097       if (!(door_state & DOOR_NO_DELAY))
2098         WaitUntilDelayReached(&door_delay, door_delay_value);
2099
2100       if (door_state & DOOR_ACTION_1)
2101       {
2102         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2103         int j = (DXSIZE - i) / 3;
2104
2105         BlitBitmap(bitmap_db_door, drawto,
2106                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2107                    DXSIZE,DYSIZE - i/2, DX, DY);
2108
2109         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2110
2111         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2112         BlitBitmapMasked(bitmap, drawto,
2113                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2114                          DX + DXSIZE - i, DY + j);
2115         BlitBitmapMasked(bitmap, drawto,
2116                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2117                          DX + DXSIZE - i, DY + 140 + j);
2118         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2119         BlitBitmapMasked(bitmap, drawto,
2120                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2121                          DX, DY);
2122         BlitBitmapMasked(bitmap, drawto,
2123                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2124                          DX, DY + 140 - j);
2125
2126         BlitBitmapMasked(bitmap, drawto,
2127                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2128                          DX, DY + 77 - j);
2129         BlitBitmapMasked(bitmap, drawto,
2130                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2131                          DX, DY + 203 - j);
2132         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2133         BlitBitmapMasked(bitmap, drawto,
2134                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2135                          DX + DXSIZE - i, DY + 77 + j);
2136         BlitBitmapMasked(bitmap, drawto,
2137                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2138                          DX + DXSIZE - i, DY + 203 + j);
2139
2140         redraw_mask |= REDRAW_DOOR_1;
2141       }
2142
2143       if (door_state & DOOR_ACTION_2)
2144       {
2145         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2146         int j = (VXSIZE - i) / 3;
2147
2148         BlitBitmap(bitmap_db_door, drawto,
2149                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2150                    VXSIZE, VYSIZE - i/2, VX, VY);
2151
2152         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2153
2154         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2155         BlitBitmapMasked(bitmap, drawto,
2156                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2157                          VX + VXSIZE-i, VY+j);
2158         SetClipOrigin(bitmap, gc,
2159                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2160         BlitBitmapMasked(bitmap, drawto,
2161                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2162                          VX, VY);
2163
2164         BlitBitmapMasked(bitmap, drawto,
2165                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2166                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2167         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2168         BlitBitmapMasked(bitmap, drawto,
2169                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2170                          i, VYSIZE / 2 - j,
2171                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2172
2173         redraw_mask |= REDRAW_DOOR_2;
2174       }
2175
2176       BackToFront();
2177
2178       if (game_status == MAINMENU)
2179         DoAnimation();
2180     }
2181   }
2182
2183   if (setup.quick_doors)
2184   {
2185     StopSound(SND_MENU_DOOR_OPENING);
2186     StopSound(SND_MENU_DOOR_CLOSING);
2187   }
2188
2189   if (door_state & DOOR_ACTION_1)
2190     door1 = door_state & DOOR_ACTION_1;
2191   if (door_state & DOOR_ACTION_2)
2192     door2 = door_state & DOOR_ACTION_2;
2193
2194   return (door1 | door2);
2195 }
2196
2197 void DrawSpecialEditorDoor()
2198 {
2199   /* draw bigger toolbox window */
2200   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2201              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2202              EX - 4, EY - 12);
2203   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2204              EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2205              EX - 4, EY - 4);
2206
2207   redraw_mask |= REDRAW_ALL;
2208 }
2209
2210 void UndrawSpecialEditorDoor()
2211 {
2212   /* draw normal tape recorder window */
2213   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2214              EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2215              EX - 4, EY - 12);
2216
2217   redraw_mask |= REDRAW_ALL;
2218 }
2219
2220 #ifndef TARGET_SDL
2221 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2222 {
2223   XImage *pixel_image;
2224   unsigned long pixel_value;
2225
2226   pixel_image = XGetImage(display, bitmap->drawable,
2227                           x, y, 1, 1, AllPlanes, ZPixmap);
2228   pixel_value = XGetPixel(pixel_image, 0, 0);
2229
2230   XDestroyImage(pixel_image);
2231
2232   return pixel_value;
2233 }
2234 #endif
2235
2236 /* ---------- new tool button stuff ---------------------------------------- */
2237
2238 /* graphic position values for tool buttons */
2239 #define TOOL_BUTTON_YES_XPOS            2
2240 #define TOOL_BUTTON_YES_YPOS            250
2241 #define TOOL_BUTTON_YES_GFX_YPOS        0
2242 #define TOOL_BUTTON_YES_XSIZE           46
2243 #define TOOL_BUTTON_YES_YSIZE           28
2244 #define TOOL_BUTTON_NO_XPOS             52
2245 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2246 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2247 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2248 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2249 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2250 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2251 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2252 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2253 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2254 #define TOOL_BUTTON_PLAYER_XSIZE        30
2255 #define TOOL_BUTTON_PLAYER_YSIZE        30
2256 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2257 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2258 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2259 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2260 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2261                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2262 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2263                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2264 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2265                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2266 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2267                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2268 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2269                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2270 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2271                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2272 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2273                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2274 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2275                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2276
2277 static struct
2278 {
2279   int xpos, ypos;
2280   int x, y;
2281   int width, height;
2282   int gadget_id;
2283   char *infotext;
2284 } toolbutton_info[NUM_TOOL_BUTTONS] =
2285 {
2286   {
2287     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2288     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2289     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2290     TOOL_CTRL_ID_YES,
2291     "yes"
2292   },
2293   {
2294     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2295     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2296     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2297     TOOL_CTRL_ID_NO,
2298     "no"
2299   },
2300   {
2301     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2302     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2303     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2304     TOOL_CTRL_ID_CONFIRM,
2305     "confirm"
2306   },
2307   {
2308     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2309     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2310     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2311     TOOL_CTRL_ID_PLAYER_1,
2312     "player 1"
2313   },
2314   {
2315     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2316     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2317     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2318     TOOL_CTRL_ID_PLAYER_2,
2319     "player 2"
2320   },
2321   {
2322     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2323     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2324     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2325     TOOL_CTRL_ID_PLAYER_3,
2326     "player 3"
2327   },
2328   {
2329     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2330     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2331     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2332     TOOL_CTRL_ID_PLAYER_4,
2333     "player 4"
2334   }
2335 };
2336
2337 void CreateToolButtons()
2338 {
2339   int i;
2340
2341   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2342   {
2343     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2344     Bitmap *deco_bitmap = None;
2345     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2346     struct GadgetInfo *gi;
2347     unsigned long event_mask;
2348     int gd_xoffset, gd_yoffset;
2349     int gd_x1, gd_x2, gd_y;
2350     int id = i;
2351
2352     event_mask = GD_EVENT_RELEASED;
2353
2354     gd_xoffset = toolbutton_info[i].xpos;
2355     gd_yoffset = toolbutton_info[i].ypos;
2356     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2357     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2358     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2359
2360     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2361     {
2362       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2363
2364       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2365                            &deco_bitmap, &deco_x, &deco_y);
2366       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2367       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2368     }
2369
2370     gi = CreateGadget(GDI_CUSTOM_ID, id,
2371                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2372                       GDI_X, DX + toolbutton_info[i].x,
2373                       GDI_Y, DY + toolbutton_info[i].y,
2374                       GDI_WIDTH, toolbutton_info[i].width,
2375                       GDI_HEIGHT, toolbutton_info[i].height,
2376                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2377                       GDI_STATE, GD_BUTTON_UNPRESSED,
2378                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2379                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2380                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2381                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2382                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2383                       GDI_DECORATION_SHIFTING, 1, 1,
2384                       GDI_EVENT_MASK, event_mask,
2385                       GDI_CALLBACK_ACTION, HandleToolButtons,
2386                       GDI_END);
2387
2388     if (gi == NULL)
2389       Error(ERR_EXIT, "cannot create gadget");
2390
2391     tool_gadget[id] = gi;
2392   }
2393 }
2394
2395 void FreeToolButtons()
2396 {
2397   int i;
2398
2399   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2400     FreeGadget(tool_gadget[i]);
2401 }
2402
2403 static void UnmapToolButtons()
2404 {
2405   int i;
2406
2407   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2408     UnmapGadget(tool_gadget[i]);
2409 }
2410
2411 static void HandleToolButtons(struct GadgetInfo *gi)
2412 {
2413   request_gadget_id = gi->custom_id;
2414 }
2415
2416 int get_next_element(int element)
2417 {
2418   switch(element)
2419   {
2420     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
2421     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
2422     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
2423     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
2424     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
2425     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
2426     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
2427
2428     default:                            return element;
2429   }
2430 }
2431
2432 int el_act_dir2img(int element, int action, int direction)
2433 {
2434   direction = MV_DIR_BIT(direction);
2435
2436   return element_info[element].direction_graphic[action][direction];
2437 }
2438
2439 int el_act2img(int element, int action)
2440 {
2441   return element_info[element].graphic[action];
2442 }
2443
2444 int el_dir2img(int element, int direction)
2445 {
2446   return el_act_dir2img(element, ACTION_DEFAULT, direction);
2447 }
2448
2449 int el2img(int element)
2450 {
2451   return element_info[element].graphic[ACTION_DEFAULT];
2452 }
2453
2454 int el2edimg(int element)
2455 {
2456   return element_info[element].editor_graphic;
2457 }