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