rnd-20030202-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES        0
25 #define TOOL_CTRL_ID_NO         1
26 #define TOOL_CTRL_ID_CONFIRM    2
27 #define TOOL_CTRL_ID_PLAYER_1   3
28 #define TOOL_CTRL_ID_PLAYER_2   4
29 #define TOOL_CTRL_ID_PLAYER_3   5
30 #define TOOL_CTRL_ID_PLAYER_4   6
31
32 #define NUM_TOOL_BUTTONS        7
33
34 /* forward declaration for internal use */
35 static 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 static int getBorderElement(int x, int y)
1341 {
1342   int border[7][2] =
1343   {
1344     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
1345     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
1346     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1347     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1348     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
1349     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
1350     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
1351   };
1352   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1353   int steel_position = (x == -1 && y == -1                      ? 0 :
1354                         x == lev_fieldx && y == -1              ? 1 :
1355                         x == -1 && y == lev_fieldy              ? 2 :
1356                         x == lev_fieldx && y == lev_fieldy      ? 3 :
1357                         x == -1 || x == lev_fieldx              ? 4 :
1358                         y == -1 || y == lev_fieldy              ? 5 : 6);
1359
1360   return border[steel_position][steel_type];
1361 }
1362
1363 void DrawScreenElement(int x, int y, int element)
1364 {
1365   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1366   DrawCrumbledSand(x, y);
1367 }
1368
1369 void DrawLevelElement(int x, int y, int element)
1370 {
1371   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1372     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1373 }
1374
1375 void DrawScreenField(int x, int y)
1376 {
1377   int lx = LEVELX(x), ly = LEVELY(y);
1378   int element, content;
1379
1380   if (!IN_LEV_FIELD(lx, ly))
1381   {
1382     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1383       element = EL_EMPTY;
1384     else
1385       element = getBorderElement(lx, ly);
1386
1387     DrawScreenElement(x, y, element);
1388     return;
1389   }
1390
1391   element = Feld[lx][ly];
1392   content = Store[lx][ly];
1393
1394   if (IS_MOVING(lx, ly))
1395   {
1396     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1397     boolean cut_mode = NO_CUTTING;
1398
1399     if (element == EL_QUICKSAND_EMPTYING ||
1400         element == EL_MAGIC_WALL_EMPTYING ||
1401         element == EL_BD_MAGIC_WALL_EMPTYING ||
1402         element == EL_AMOEBA_DRIPPING)
1403       cut_mode = CUT_ABOVE;
1404     else if (element == EL_QUICKSAND_FILLING ||
1405              element == EL_MAGIC_WALL_FILLING ||
1406              element == EL_BD_MAGIC_WALL_FILLING)
1407       cut_mode = CUT_BELOW;
1408
1409     if (cut_mode == CUT_ABOVE)
1410       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1411     else
1412       DrawScreenElement(x, y, EL_EMPTY);
1413
1414     if (horiz_move)
1415       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1416     else if (cut_mode == NO_CUTTING)
1417       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1418     else
1419       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1420
1421     if (content == EL_ACID)
1422       DrawLevelElementThruMask(lx, ly + 1, EL_ACID);
1423   }
1424   else if (IS_BLOCKED(lx, ly))
1425   {
1426     int oldx, oldy;
1427     int sx, sy;
1428     int horiz_move;
1429     boolean cut_mode = NO_CUTTING;
1430     int element_old, content_old;
1431
1432     Blocked2Moving(lx, ly, &oldx, &oldy);
1433     sx = SCREENX(oldx);
1434     sy = SCREENY(oldy);
1435     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1436                   MovDir[oldx][oldy] == MV_RIGHT);
1437
1438     element_old = Feld[oldx][oldy];
1439     content_old = Store[oldx][oldy];
1440
1441     if (element_old == EL_QUICKSAND_EMPTYING ||
1442         element_old == EL_MAGIC_WALL_EMPTYING ||
1443         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1444         element_old == EL_AMOEBA_DRIPPING)
1445       cut_mode = CUT_ABOVE;
1446
1447     DrawScreenElement(x, y, EL_EMPTY);
1448
1449     if (horiz_move)
1450       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1451                                NO_CUTTING);
1452     else if (cut_mode == NO_CUTTING)
1453       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1454                                cut_mode);
1455     else
1456       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1457                                cut_mode);
1458   }
1459   else if (IS_DRAWABLE(element))
1460     DrawScreenElement(x, y, element);
1461   else
1462     DrawScreenElement(x, y, EL_EMPTY);
1463 }
1464
1465 void DrawLevelField(int x, int y)
1466 {
1467   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1468     DrawScreenField(SCREENX(x), SCREENY(y));
1469   else if (IS_MOVING(x, y))
1470   {
1471     int newx,newy;
1472
1473     Moving2Blocked(x, y, &newx, &newy);
1474     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1475       DrawScreenField(SCREENX(newx), SCREENY(newy));
1476   }
1477   else if (IS_BLOCKED(x, y))
1478   {
1479     int oldx, oldy;
1480
1481     Blocked2Moving(x, y, &oldx, &oldy);
1482     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1483       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1484   }
1485 }
1486
1487 void DrawMiniElement(int x, int y, int element)
1488 {
1489   int graphic;
1490
1491   graphic = el2edimg(element);
1492   DrawMiniGraphic(x, y, graphic);
1493 }
1494
1495 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1496 {
1497   int x = sx + scroll_x, y = sy + scroll_y;
1498
1499   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1500     DrawMiniElement(sx, sy, EL_EMPTY);
1501   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1502     DrawMiniElement(sx, sy, Feld[x][y]);
1503   else
1504     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1505 }
1506
1507 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1508 {
1509   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1510   int mini_startx = src_bitmap->width * 3 / 4;
1511   int mini_starty = src_bitmap->height * 2 / 3;
1512   int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1513   int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1514
1515   if (src_x + MICRO_TILEX > src_bitmap->width ||
1516       src_y + MICRO_TILEY > src_bitmap->height)
1517   {
1518     /* graphic of desired size seems not to be contained in this image;
1519        dirty workaround: get it from the middle of the normal sized image */
1520
1521     getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1522     src_x += (TILEX / 2 - MICRO_TILEX / 2);
1523     src_y += (TILEY / 2 - MICRO_TILEY / 2);
1524   }
1525
1526   *bitmap = src_bitmap;
1527   *x = src_x;
1528   *y = src_y;
1529 }
1530
1531 void DrawMicroElement(int xpos, int ypos, int element)
1532 {
1533   Bitmap *src_bitmap;
1534   int src_x, src_y;
1535   int graphic = el2preimg(element);
1536
1537   getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1538   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1539              xpos, ypos);
1540 }
1541
1542 void DrawLevel()
1543 {
1544   int x,y;
1545
1546   SetDrawBackgroundMask(REDRAW_NONE);
1547   ClearWindow();
1548
1549   for(x=BX1; x<=BX2; x++)
1550     for(y=BY1; y<=BY2; y++)
1551       DrawScreenField(x, y);
1552
1553   redraw_mask |= REDRAW_FIELD;
1554 }
1555
1556 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1557 {
1558   int x,y;
1559
1560   for(x=0; x<size_x; x++)
1561     for(y=0; y<size_y; y++)
1562       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1563
1564   redraw_mask |= REDRAW_FIELD;
1565 }
1566
1567 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1568 {
1569   int x, y;
1570
1571   DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1572
1573   if (lev_fieldx < STD_LEV_FIELDX)
1574     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1575   if (lev_fieldy < STD_LEV_FIELDY)
1576     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1577
1578   xpos += MICRO_TILEX;
1579   ypos += MICRO_TILEY;
1580
1581   for(x=-1; x<=STD_LEV_FIELDX; x++)
1582   {
1583     for(y=-1; y<=STD_LEV_FIELDY; y++)
1584     {
1585       int lx = from_x + x, ly = from_y + y;
1586
1587       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1588         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1589                          Ur[lx][ly]);
1590       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1591                && BorderElement != EL_EMPTY)
1592         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1593                          getBorderElement(lx, ly));
1594     }
1595   }
1596
1597   redraw_mask |= REDRAW_MICROLEVEL;
1598 }
1599
1600 #define MICROLABEL_EMPTY                0
1601 #define MICROLABEL_LEVEL_NAME           1
1602 #define MICROLABEL_CREATED_BY           2
1603 #define MICROLABEL_LEVEL_AUTHOR         3
1604 #define MICROLABEL_IMPORTED_FROM        4
1605 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1606
1607 #define MAX_MICROLABEL_SIZE             (SXSIZE / FONT4_XSIZE)
1608
1609 static void DrawMicroLevelLabelExt(int mode)
1610 {
1611   char label_text[MAX_MICROLABEL_SIZE + 1];
1612
1613   DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1614
1615   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1616                        mode == MICROLABEL_CREATED_BY ? "created by" :
1617                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1618                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1619                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1620                        leveldir_current->imported_from : ""),
1621           MAX_MICROLABEL_SIZE);
1622   label_text[MAX_MICROLABEL_SIZE] = '\0';
1623
1624   if (strlen(label_text) > 0)
1625   {
1626     int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1627     int lypos = MICROLABEL_YPOS;
1628
1629     DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1630   }
1631
1632   redraw_mask |= REDRAW_MICROLEVEL;
1633 }
1634
1635 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1636 {
1637   static unsigned long scroll_delay = 0;
1638   static unsigned long label_delay = 0;
1639   static int from_x, from_y, scroll_direction;
1640   static int label_state, label_counter;
1641
1642   if (restart)
1643   {
1644     from_x = from_y = 0;
1645     scroll_direction = MV_RIGHT;
1646     label_state = 1;
1647     label_counter = 0;
1648
1649     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1650     DrawMicroLevelLabelExt(label_state);
1651
1652     /* initialize delay counters */
1653     DelayReached(&scroll_delay, 0);
1654     DelayReached(&label_delay, 0);
1655
1656     return;
1657   }
1658
1659   /* scroll micro level, if needed */
1660   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1661       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1662   {
1663     switch (scroll_direction)
1664     {
1665       case MV_LEFT:
1666         if (from_x > 0)
1667           from_x--;
1668         else
1669           scroll_direction = MV_UP;
1670         break;
1671
1672       case MV_RIGHT:
1673         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1674           from_x++;
1675         else
1676           scroll_direction = MV_DOWN;
1677         break;
1678
1679       case MV_UP:
1680         if (from_y > 0)
1681           from_y--;
1682         else
1683           scroll_direction = MV_RIGHT;
1684         break;
1685
1686       case MV_DOWN:
1687         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1688           from_y++;
1689         else
1690           scroll_direction = MV_LEFT;
1691         break;
1692
1693       default:
1694         break;
1695     }
1696
1697     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1698   }
1699
1700   /* redraw micro level label, if needed */
1701   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1702       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1703       strcmp(level.author, leveldir_current->name) != 0 &&
1704       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1705   {
1706     int max_label_counter = 23;
1707
1708     if (leveldir_current->imported_from != NULL)
1709       max_label_counter += 14;
1710
1711     label_counter = (label_counter + 1) % max_label_counter;
1712     label_state = (label_counter >= 0 && label_counter <= 7 ?
1713                    MICROLABEL_LEVEL_NAME :
1714                    label_counter >= 9 && label_counter <= 12 ?
1715                    MICROLABEL_CREATED_BY :
1716                    label_counter >= 14 && label_counter <= 21 ?
1717                    MICROLABEL_LEVEL_AUTHOR :
1718                    label_counter >= 23 && label_counter <= 26 ?
1719                    MICROLABEL_IMPORTED_FROM :
1720                    label_counter >= 28 && label_counter <= 35 ?
1721                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1722     DrawMicroLevelLabelExt(label_state);
1723   }
1724 }
1725
1726 int REQ_in_range(int x, int y)
1727 {
1728   if (y > DY+249 && y < DY+278)
1729   {
1730     if (x > DX+1 && x < DX+48)
1731       return 1;
1732     else if (x > DX+51 && x < DX+98) 
1733       return 2;
1734   }
1735   return 0;
1736 }
1737
1738 #define MAX_REQUEST_LINES               13
1739 #define MAX_REQUEST_LINE_LEN            7
1740
1741 boolean Request(char *text, unsigned int req_state)
1742 {
1743   int mx, my, ty, result = -1;
1744   unsigned int old_door_state;
1745
1746 #if defined(PLATFORM_UNIX)
1747   /* pause network game while waiting for request to answer */
1748   if (options.network &&
1749       game_status == PLAYING &&
1750       req_state & REQUEST_WAIT_FOR)
1751     SendToServer_PausePlaying();
1752 #endif
1753
1754   old_door_state = GetDoorState();
1755
1756   UnmapAllGadgets();
1757
1758   CloseDoor(DOOR_CLOSE_1);
1759
1760   /* save old door content */
1761   BlitBitmap(bitmap_db_door, bitmap_db_door,
1762              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1763              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1764
1765   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1766
1767   /* clear door drawing field */
1768   DrawBackground(DX, DY, DXSIZE, DYSIZE);
1769
1770   /* write text for request */
1771   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1772   {
1773     char text_line[MAX_REQUEST_LINE_LEN + 1];
1774     int tx, tl, tc;
1775
1776     if (!*text)
1777       break;
1778
1779     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1780     {
1781       tc = *(text + tx);
1782       if (!tc || tc == ' ')
1783         break;
1784     }
1785
1786     if (!tl)
1787     { 
1788       text++; 
1789       ty--; 
1790       continue; 
1791     }
1792
1793     strncpy(text_line, text, tl);
1794     text_line[tl] = 0;
1795
1796     DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1797              text_line, FS_SMALL, FC_YELLOW);
1798
1799     text += tl + (tc == ' ' ? 1 : 0);
1800   }
1801
1802   if (req_state & REQ_ASK)
1803   {
1804     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1805     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1806   }
1807   else if (req_state & REQ_CONFIRM)
1808   {
1809     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1810   }
1811   else if (req_state & REQ_PLAYER)
1812   {
1813     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1814     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1815     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1816     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1817   }
1818
1819   /* copy request gadgets to door backbuffer */
1820   BlitBitmap(drawto, bitmap_db_door,
1821              DX, DY, DXSIZE, DYSIZE,
1822              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1823
1824   OpenDoor(DOOR_OPEN_1);
1825
1826 #if 0
1827   ClearEventQueue();
1828 #endif
1829
1830   if (!(req_state & REQUEST_WAIT_FOR))
1831   {
1832     SetDrawBackgroundMask(REDRAW_FIELD);
1833
1834     return FALSE;
1835   }
1836
1837   if (game_status != MAINMENU)
1838     InitAnimation();
1839
1840   button_status = MB_RELEASED;
1841
1842   request_gadget_id = -1;
1843
1844   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1845
1846   while(result < 0)
1847   {
1848     if (PendingEvent())
1849     {
1850       Event event;
1851
1852       NextEvent(&event);
1853
1854       switch(event.type)
1855       {
1856         case EVENT_BUTTONPRESS:
1857         case EVENT_BUTTONRELEASE:
1858         case EVENT_MOTIONNOTIFY:
1859         {
1860           if (event.type == EVENT_MOTIONNOTIFY)
1861           {
1862             if (!PointerInWindow(window))
1863               continue; /* window and pointer are on different screens */
1864
1865             if (!button_status)
1866               continue;
1867
1868             motion_status = TRUE;
1869             mx = ((MotionEvent *) &event)->x;
1870             my = ((MotionEvent *) &event)->y;
1871           }
1872           else
1873           {
1874             motion_status = FALSE;
1875             mx = ((ButtonEvent *) &event)->x;
1876             my = ((ButtonEvent *) &event)->y;
1877             if (event.type == EVENT_BUTTONPRESS)
1878               button_status = ((ButtonEvent *) &event)->button;
1879             else
1880               button_status = MB_RELEASED;
1881           }
1882
1883           /* this sets 'request_gadget_id' */
1884           HandleGadgets(mx, my, button_status);
1885
1886           switch(request_gadget_id)
1887           {
1888             case TOOL_CTRL_ID_YES:
1889               result = TRUE;
1890               break;
1891             case TOOL_CTRL_ID_NO:
1892               result = FALSE;
1893               break;
1894             case TOOL_CTRL_ID_CONFIRM:
1895               result = TRUE | FALSE;
1896               break;
1897
1898             case TOOL_CTRL_ID_PLAYER_1:
1899               result = 1;
1900               break;
1901             case TOOL_CTRL_ID_PLAYER_2:
1902               result = 2;
1903               break;
1904             case TOOL_CTRL_ID_PLAYER_3:
1905               result = 3;
1906               break;
1907             case TOOL_CTRL_ID_PLAYER_4:
1908               result = 4;
1909               break;
1910
1911             default:
1912               break;
1913           }
1914
1915           break;
1916         }
1917
1918         case EVENT_KEYPRESS:
1919           switch(GetEventKey((KeyEvent *)&event, TRUE))
1920           {
1921             case KSYM_Return:
1922               result = 1;
1923               break;
1924
1925             case KSYM_Escape:
1926               result = 0;
1927               break;
1928
1929             default:
1930               break;
1931           }
1932           if (req_state & REQ_PLAYER)
1933             result = 0;
1934           break;
1935
1936         case EVENT_KEYRELEASE:
1937           ClearPlayerAction();
1938           break;
1939
1940         default:
1941           HandleOtherEvents(&event);
1942           break;
1943       }
1944     }
1945     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1946     {
1947       int joy = AnyJoystick();
1948
1949       if (joy & JOY_BUTTON_1)
1950         result = 1;
1951       else if (joy & JOY_BUTTON_2)
1952         result = 0;
1953     }
1954
1955     DoAnimation();
1956
1957     /* don't eat all CPU time */
1958     Delay(10);
1959   }
1960
1961   if (game_status != MAINMENU)
1962     StopAnimation();
1963
1964   UnmapToolButtons();
1965
1966   if (!(req_state & REQ_STAY_OPEN))
1967   {
1968     CloseDoor(DOOR_CLOSE_1);
1969
1970     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
1971     {
1972       BlitBitmap(bitmap_db_door, bitmap_db_door,
1973                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
1974                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
1975       OpenDoor(DOOR_OPEN_1);
1976     }
1977   }
1978
1979   RemapAllGadgets();
1980
1981   SetDrawBackgroundMask(REDRAW_FIELD);
1982
1983 #if defined(PLATFORM_UNIX)
1984   /* continue network game after request */
1985   if (options.network &&
1986       game_status == PLAYING &&
1987       req_state & REQUEST_WAIT_FOR)
1988     SendToServer_ContinuePlaying();
1989 #endif
1990
1991   return result;
1992 }
1993
1994 unsigned int OpenDoor(unsigned int door_state)
1995 {
1996   unsigned int new_door_state;
1997
1998   if (door_state & DOOR_COPY_BACK)
1999   {
2000     BlitBitmap(bitmap_db_door, bitmap_db_door,
2001                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2002                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2003     door_state &= ~DOOR_COPY_BACK;
2004   }
2005
2006   new_door_state = MoveDoor(door_state);
2007
2008   return(new_door_state);
2009 }
2010
2011 unsigned int CloseDoor(unsigned int door_state)
2012 {
2013   unsigned int new_door_state;
2014
2015   BlitBitmap(backbuffer, bitmap_db_door,
2016              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2017   BlitBitmap(backbuffer, bitmap_db_door,
2018              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2019
2020   new_door_state = MoveDoor(door_state);
2021
2022   return(new_door_state);
2023 }
2024
2025 unsigned int GetDoorState()
2026 {
2027   return MoveDoor(DOOR_GET_STATE);
2028 }
2029
2030 unsigned int SetDoorState(unsigned int door_state)
2031 {
2032   return MoveDoor(door_state | DOOR_SET_STATE);
2033 }
2034
2035 unsigned int MoveDoor(unsigned int door_state)
2036 {
2037   static int door1 = DOOR_OPEN_1;
2038   static int door2 = DOOR_CLOSE_2;
2039   static unsigned long door_delay = 0;
2040   int x, start, stepsize = 2;
2041   unsigned long door_delay_value = stepsize * 5;
2042
2043   if (door_state == DOOR_GET_STATE)
2044     return(door1 | door2);
2045
2046   if (door_state & DOOR_SET_STATE)
2047   {
2048     if (door_state & DOOR_ACTION_1)
2049       door1 = door_state & DOOR_ACTION_1;
2050     if (door_state & DOOR_ACTION_2)
2051       door2 = door_state & DOOR_ACTION_2;
2052
2053     return(door1 | door2);
2054   }
2055
2056   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2057     door_state &= ~DOOR_OPEN_1;
2058   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2059     door_state &= ~DOOR_CLOSE_1;
2060   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2061     door_state &= ~DOOR_OPEN_2;
2062   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2063     door_state &= ~DOOR_CLOSE_2;
2064
2065   if (setup.quick_doors)
2066   {
2067     stepsize = 20;
2068     door_delay_value = 0;
2069
2070     StopSound(SND_MENU_DOOR_OPENING);
2071     StopSound(SND_MENU_DOOR_CLOSING);
2072   }
2073
2074   if (global.autoplay_leveldir)
2075   {
2076     door_state |= DOOR_NO_DELAY;
2077     door_state &= ~DOOR_CLOSE_ALL;
2078   }
2079
2080   if (door_state & DOOR_ACTION)
2081   {
2082     if (!(door_state & DOOR_NO_DELAY))
2083     {
2084       /* opening door sound has priority over simultaneously closing door */
2085       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2086         PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2087       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2088         PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2089     }
2090
2091     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2092
2093     for(x=start; x<=DXSIZE; x+=stepsize)
2094     {
2095       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2096       GC gc = bitmap->stored_clip_gc;
2097
2098       if (!(door_state & DOOR_NO_DELAY))
2099         WaitUntilDelayReached(&door_delay, door_delay_value);
2100
2101       if (door_state & DOOR_ACTION_1)
2102       {
2103         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2104         int j = (DXSIZE - i) / 3;
2105
2106         BlitBitmap(bitmap_db_door, drawto,
2107                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2108                    DXSIZE,DYSIZE - i/2, DX, DY);
2109
2110         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2111
2112         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2113         BlitBitmapMasked(bitmap, drawto,
2114                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2115                          DX + DXSIZE - i, DY + j);
2116         BlitBitmapMasked(bitmap, drawto,
2117                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2118                          DX + DXSIZE - i, DY + 140 + j);
2119         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2120         BlitBitmapMasked(bitmap, drawto,
2121                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2122                          DX, DY);
2123         BlitBitmapMasked(bitmap, drawto,
2124                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2125                          DX, DY + 140 - j);
2126
2127         BlitBitmapMasked(bitmap, drawto,
2128                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2129                          DX, DY + 77 - j);
2130         BlitBitmapMasked(bitmap, drawto,
2131                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2132                          DX, DY + 203 - j);
2133         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2134         BlitBitmapMasked(bitmap, drawto,
2135                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2136                          DX + DXSIZE - i, DY + 77 + j);
2137         BlitBitmapMasked(bitmap, drawto,
2138                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2139                          DX + DXSIZE - i, DY + 203 + j);
2140
2141         redraw_mask |= REDRAW_DOOR_1;
2142       }
2143
2144       if (door_state & DOOR_ACTION_2)
2145       {
2146         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2147         int j = (VXSIZE - i) / 3;
2148
2149         BlitBitmap(bitmap_db_door, drawto,
2150                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2151                    VXSIZE, VYSIZE - i/2, VX, VY);
2152
2153         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2154
2155         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2156         BlitBitmapMasked(bitmap, drawto,
2157                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2158                          VX + VXSIZE-i, VY+j);
2159         SetClipOrigin(bitmap, gc,
2160                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2161         BlitBitmapMasked(bitmap, drawto,
2162                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2163                          VX, VY);
2164
2165         BlitBitmapMasked(bitmap, drawto,
2166                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2167                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2168         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2169         BlitBitmapMasked(bitmap, drawto,
2170                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2171                          i, VYSIZE / 2 - j,
2172                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2173
2174         redraw_mask |= REDRAW_DOOR_2;
2175       }
2176
2177       BackToFront();
2178
2179       if (game_status == MAINMENU)
2180         DoAnimation();
2181     }
2182   }
2183
2184   if (setup.quick_doors)
2185   {
2186     StopSound(SND_MENU_DOOR_OPENING);
2187     StopSound(SND_MENU_DOOR_CLOSING);
2188   }
2189
2190   if (door_state & DOOR_ACTION_1)
2191     door1 = door_state & DOOR_ACTION_1;
2192   if (door_state & DOOR_ACTION_2)
2193     door2 = door_state & DOOR_ACTION_2;
2194
2195   return (door1 | door2);
2196 }
2197
2198 void DrawSpecialEditorDoor()
2199 {
2200   /* draw bigger toolbox window */
2201   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2202              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2203              EX - 4, EY - 12);
2204   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2205              EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2206              EX - 4, EY - 4);
2207
2208   redraw_mask |= REDRAW_ALL;
2209 }
2210
2211 void UndrawSpecialEditorDoor()
2212 {
2213   /* draw normal tape recorder window */
2214   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2215              EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2216              EX - 4, EY - 12);
2217
2218   redraw_mask |= REDRAW_ALL;
2219 }
2220
2221 #ifndef TARGET_SDL
2222 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2223 {
2224   XImage *pixel_image;
2225   unsigned long pixel_value;
2226
2227   pixel_image = XGetImage(display, bitmap->drawable,
2228                           x, y, 1, 1, AllPlanes, ZPixmap);
2229   pixel_value = XGetPixel(pixel_image, 0, 0);
2230
2231   XDestroyImage(pixel_image);
2232
2233   return pixel_value;
2234 }
2235 #endif
2236
2237 /* ---------- new tool button stuff ---------------------------------------- */
2238
2239 /* graphic position values for tool buttons */
2240 #define TOOL_BUTTON_YES_XPOS            2
2241 #define TOOL_BUTTON_YES_YPOS            250
2242 #define TOOL_BUTTON_YES_GFX_YPOS        0
2243 #define TOOL_BUTTON_YES_XSIZE           46
2244 #define TOOL_BUTTON_YES_YSIZE           28
2245 #define TOOL_BUTTON_NO_XPOS             52
2246 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2247 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2248 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2249 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2250 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2251 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2252 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2253 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2254 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2255 #define TOOL_BUTTON_PLAYER_XSIZE        30
2256 #define TOOL_BUTTON_PLAYER_YSIZE        30
2257 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2258 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2259 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2260 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2261 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2262                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2263 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2264                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2265 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2266                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2267 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2268                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2269 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2270                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2271 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2272                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2273 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2274                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2275 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2276                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2277
2278 static struct
2279 {
2280   int xpos, ypos;
2281   int x, y;
2282   int width, height;
2283   int gadget_id;
2284   char *infotext;
2285 } toolbutton_info[NUM_TOOL_BUTTONS] =
2286 {
2287   {
2288     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2289     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2290     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2291     TOOL_CTRL_ID_YES,
2292     "yes"
2293   },
2294   {
2295     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2296     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2297     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2298     TOOL_CTRL_ID_NO,
2299     "no"
2300   },
2301   {
2302     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2303     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2304     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2305     TOOL_CTRL_ID_CONFIRM,
2306     "confirm"
2307   },
2308   {
2309     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2310     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2311     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2312     TOOL_CTRL_ID_PLAYER_1,
2313     "player 1"
2314   },
2315   {
2316     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2317     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2318     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2319     TOOL_CTRL_ID_PLAYER_2,
2320     "player 2"
2321   },
2322   {
2323     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2324     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2325     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2326     TOOL_CTRL_ID_PLAYER_3,
2327     "player 3"
2328   },
2329   {
2330     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2331     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2332     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2333     TOOL_CTRL_ID_PLAYER_4,
2334     "player 4"
2335   }
2336 };
2337
2338 void CreateToolButtons()
2339 {
2340   int i;
2341
2342   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2343   {
2344     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2345     Bitmap *deco_bitmap = None;
2346     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2347     struct GadgetInfo *gi;
2348     unsigned long event_mask;
2349     int gd_xoffset, gd_yoffset;
2350     int gd_x1, gd_x2, gd_y;
2351     int id = i;
2352
2353     event_mask = GD_EVENT_RELEASED;
2354
2355     gd_xoffset = toolbutton_info[i].xpos;
2356     gd_yoffset = toolbutton_info[i].ypos;
2357     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2358     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2359     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2360
2361     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2362     {
2363       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2364
2365       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2366                            &deco_bitmap, &deco_x, &deco_y);
2367       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2368       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2369     }
2370
2371     gi = CreateGadget(GDI_CUSTOM_ID, id,
2372                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2373                       GDI_X, DX + toolbutton_info[i].x,
2374                       GDI_Y, DY + toolbutton_info[i].y,
2375                       GDI_WIDTH, toolbutton_info[i].width,
2376                       GDI_HEIGHT, toolbutton_info[i].height,
2377                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2378                       GDI_STATE, GD_BUTTON_UNPRESSED,
2379                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2380                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2381                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2382                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2383                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2384                       GDI_DECORATION_SHIFTING, 1, 1,
2385                       GDI_EVENT_MASK, event_mask,
2386                       GDI_CALLBACK_ACTION, HandleToolButtons,
2387                       GDI_END);
2388
2389     if (gi == NULL)
2390       Error(ERR_EXIT, "cannot create gadget");
2391
2392     tool_gadget[id] = gi;
2393   }
2394 }
2395
2396 void FreeToolButtons()
2397 {
2398   int i;
2399
2400   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2401     FreeGadget(tool_gadget[i]);
2402 }
2403
2404 static void UnmapToolButtons()
2405 {
2406   int i;
2407
2408   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2409     UnmapGadget(tool_gadget[i]);
2410 }
2411
2412 static void HandleToolButtons(struct GadgetInfo *gi)
2413 {
2414   request_gadget_id = gi->custom_id;
2415 }
2416
2417 int get_next_element(int element)
2418 {
2419   switch(element)
2420   {
2421     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
2422     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
2423     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
2424     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
2425     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
2426     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
2427     case EL_AMOEBA_DRIPPING:            return EL_AMOEBA_WET;
2428
2429     default:                            return element;
2430   }
2431 }
2432
2433 int el_act_dir2img(int element, int action, int direction)
2434 {
2435   direction = MV_DIR_BIT(direction);
2436
2437   return element_info[element].direction_graphic[action][direction];
2438 }
2439
2440 int el_act2img(int element, int action)
2441 {
2442   return element_info[element].graphic[action];
2443 }
2444
2445 int el_dir2img(int element, int direction)
2446 {
2447   return el_act_dir2img(element, ACTION_DEFAULT, direction);
2448 }
2449
2450 int el2img(int element)
2451 {
2452   return element_info[element].graphic[ACTION_DEFAULT];
2453 }
2454
2455 int el2edimg(int element)
2456 {
2457   return element_info[element].editor_graphic;
2458 }
2459
2460 int el2preimg(int element)
2461 {
2462   return element_info[element].preview_graphic;
2463 }