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