rnd-20030730-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 static int el_act_dir2crm(int, int, int);
38
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
41
42 void SetDrawtoField(int mode)
43 {
44   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
45   {
46     FX = TILEX;
47     FY = TILEY;
48     BX1 = -1;
49     BY1 = -1;
50     BX2 = SCR_FIELDX;
51     BY2 = SCR_FIELDY;
52     redraw_x1 = 1;
53     redraw_y1 = 1;
54
55     drawto_field = fieldbuffer;
56   }
57   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
58   {
59     FX = SX;
60     FY = SY;
61     BX1 = 0;
62     BY1 = 0;
63     BX2 = SCR_FIELDX - 1;
64     BY2 = SCR_FIELDY - 1;
65     redraw_x1 = 0;
66     redraw_y1 = 0;
67
68     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
69   }
70 }
71
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 {
74   if (game_status == GAME_MODE_PLAYING)
75   {
76     if (force_redraw)
77     {
78       x = gfx.sx - TILEX;
79       y = gfx.sy - TILEY;
80       width = gfx.sxsize + 2 * TILEX;
81       height = gfx.sysize + 2 * TILEY;
82     }
83
84     if (force_redraw || setup.direct_draw)
85     {
86       int xx, yy;
87       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89
90       if (setup.direct_draw)
91         SetDrawtoField(DRAW_BACKBUFFER);
92
93       for(xx=BX1; xx<=BX2; xx++)
94         for(yy=BY1; yy<=BY2; yy++)
95           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96             DrawScreenField(xx, yy);
97       DrawAllPlayers();
98
99       if (setup.direct_draw)
100         SetDrawtoField(DRAW_DIRECT);
101     }
102
103     if (setup.soft_scrolling)
104     {
105       int fx = FX, fy = FY;
106
107       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
109
110       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
111     }
112   }
113
114   BlitBitmap(drawto, window, x, y, width, height, x, y);
115 }
116
117 void BackToFront()
118 {
119   int x,y;
120   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121
122   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
123     redraw_mask &= ~REDRAW_MAIN;
124
125   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126     redraw_mask |= REDRAW_FIELD;
127
128   if (redraw_mask & REDRAW_FIELD)
129     redraw_mask &= ~REDRAW_TILES;
130
131   if (redraw_mask == REDRAW_NONE)
132     return;
133
134   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
135   {
136     static boolean last_frame_skipped = FALSE;
137     boolean skip_even_when_not_scrolling = TRUE;
138     boolean just_scrolling = (ScreenMovDir != 0);
139     boolean verbose = FALSE;
140
141     if (global.fps_slowdown_factor > 1 &&
142         (FrameCounter % global.fps_slowdown_factor) &&
143         (just_scrolling || skip_even_when_not_scrolling))
144     {
145       redraw_mask &= ~REDRAW_MAIN;
146
147       last_frame_skipped = TRUE;
148
149       if (verbose)
150         printf("FRAME SKIPPED\n");
151     }
152     else
153     {
154       if (last_frame_skipped)
155         redraw_mask |= REDRAW_FIELD;
156
157       last_frame_skipped = FALSE;
158
159       if (verbose)
160         printf("frame not skipped\n");
161     }
162   }
163
164   /* synchronize X11 graphics at this point; if we would synchronize the
165      display immediately after the buffer switching (after the XFlush),
166      this could mean that we have to wait for the graphics to complete,
167      although we could go on doing calculations for the next frame */
168
169   SyncDisplay();
170
171   if (redraw_mask & REDRAW_ALL)
172   {
173     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
174     redraw_mask = 0;
175   }
176
177   if (redraw_mask & REDRAW_FIELD)
178   {
179     if (game_status != GAME_MODE_PLAYING ||
180         redraw_mask & REDRAW_FROM_BACKBUFFER)
181     {
182       BlitBitmap(backbuffer, window,
183                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
184     }
185     else
186     {
187       int fx = FX, fy = FY;
188
189       if (setup.soft_scrolling)
190       {
191         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
192         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
193       }
194
195       if (setup.soft_scrolling ||
196           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
197           ABS(ScreenMovPos) == ScrollStepSize ||
198           redraw_tiles > REDRAWTILES_THRESHOLD)
199       {
200         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
201
202 #ifdef DEBUG
203 #if 0
204         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205                ScreenGfxPos,
206                (setup.soft_scrolling ?
207                 "setup.soft_scrolling" :
208                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
209                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
210                 ABS(ScreenGfxPos) == ScrollStepSize ?
211                 "ABS(ScreenGfxPos) == ScrollStepSize" :
212                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
213 #endif
214 #endif
215       }
216     }
217
218     redraw_mask &= ~REDRAW_MAIN;
219   }
220
221   if (redraw_mask & REDRAW_DOORS)
222   {
223     if (redraw_mask & REDRAW_DOOR_1)
224       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
225     if (redraw_mask & REDRAW_DOOR_2)
226     {
227       if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
228         BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229       else
230       {
231         if (redraw_mask & REDRAW_VIDEO_1)
232           BlitBitmap(backbuffer, window,
233                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
234                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
235                      VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
236         if (redraw_mask & REDRAW_VIDEO_2)
237           BlitBitmap(backbuffer, window,
238                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
239                      VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
240                      VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
241         if (redraw_mask & REDRAW_VIDEO_3)
242           BlitBitmap(backbuffer, window,
243                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
244                      VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
245                      VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
246       }
247     }
248
249     if (redraw_mask & REDRAW_DOOR_3)
250       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
251
252     redraw_mask &= ~REDRAW_DOORS;
253   }
254
255   if (redraw_mask & REDRAW_MICROLEVEL)
256   {
257     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
258                SX, SY + 10 * TILEY);
259
260     redraw_mask &= ~REDRAW_MICROLEVEL;
261   }
262
263   if (redraw_mask & REDRAW_TILES)
264   {
265     for(x=0; x<SCR_FIELDX; x++)
266       for(y=0; y<SCR_FIELDY; y++)
267         if (redraw[redraw_x1 + x][redraw_y1 + y])
268           BlitBitmap(buffer, window,
269                      FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270                      SX + x * TILEX, SY + y * TILEY);
271   }
272
273   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
274   {
275     char text[100];
276     char info1[100];
277
278     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279     if (!global.fps_slowdown)
280       info1[0] = '\0';
281
282     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
284   }
285
286   FlushDisplay();
287
288   for(x=0; x<MAX_BUF_XSIZE; x++)
289     for(y=0; y<MAX_BUF_YSIZE; y++)
290       redraw[x][y] = 0;
291   redraw_tiles = 0;
292   redraw_mask = REDRAW_NONE;
293 }
294
295 void FadeToFront()
296 {
297 #if 0
298   long fading_delay = 300;
299
300   if (setup.fading && (redraw_mask & REDRAW_FIELD))
301   {
302 #endif
303
304 #if 0
305     int x,y;
306
307     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
308     FlushDisplay();
309
310     for(i=0;i<2*FULL_SYSIZE;i++)
311     {
312       for(y=0;y<FULL_SYSIZE;y++)
313       {
314         BlitBitmap(backbuffer, window,
315                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
316       }
317       FlushDisplay();
318       Delay(10);
319     }
320 #endif
321
322 #if 0
323     for(i=1;i<FULL_SYSIZE;i+=2)
324       BlitBitmap(backbuffer, window,
325                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
326     FlushDisplay();
327     Delay(fading_delay);
328 #endif
329
330 #if 0
331     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332     BlitBitmapMasked(backbuffer, window,
333                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
334                      REAL_SX,REAL_SY);
335     FlushDisplay();
336     Delay(fading_delay);
337
338     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339     BlitBitmapMasked(backbuffer, window,
340                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
341                      REAL_SX,REAL_SY);
342     FlushDisplay();
343     Delay(fading_delay);
344
345     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346     BlitBitmapMasked(backbuffer, window,
347                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
348                      REAL_SX,REAL_SY);
349     FlushDisplay();
350     Delay(fading_delay);
351
352     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353     BlitBitmapMasked(backbuffer, window,
354                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
355                      REAL_SX,REAL_SY);
356     FlushDisplay();
357     Delay(fading_delay);
358
359     redraw_mask &= ~REDRAW_MAIN;
360   }
361 #endif
362
363   BackToFront();
364 }
365
366 void SetMainBackgroundImage(int graphic)
367 {
368   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
369                           graphic_info[graphic].bitmap ?
370                           graphic_info[graphic].bitmap :
371                           graphic_info[IMG_BACKGROUND].bitmap);
372 }
373
374 void SetDoorBackgroundImage(int graphic)
375 {
376   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
377                           graphic_info[graphic].bitmap ?
378                           graphic_info[graphic].bitmap :
379                           graphic_info[IMG_BACKGROUND].bitmap);
380 }
381
382 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 {
384   ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385
386   redraw_mask |= REDRAW_FIELD;
387 }
388
389 void ClearWindow()
390 {
391   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392
393   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
394   {
395     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
396     SetDrawtoField(DRAW_BUFFERED);
397   }
398   else
399     SetDrawtoField(DRAW_BACKBUFFER);
400
401   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
402   {
403     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
404     SetDrawtoField(DRAW_DIRECT);
405   }
406 }
407
408 void MarkTileDirty(int x, int y)
409 {
410   int xx = redraw_x1 + x;
411   int yy = redraw_y1 + y;
412
413   if (!redraw[xx][yy])
414     redraw_tiles++;
415
416   redraw[xx][yy] = TRUE;
417   redraw_mask |= REDRAW_TILES;
418 }
419
420 void SetBorderElement()
421 {
422   int x, y;
423
424   BorderElement = EL_EMPTY;
425
426   for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427   {
428     for(x=0; x<lev_fieldx; x++)
429     {
430       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
431         BorderElement = EL_STEELWALL;
432
433       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
434         x = lev_fieldx - 2;
435     }
436   }
437 }
438
439 void SetRandomAnimationValue(int x, int y)
440 {
441   gfx.anim_random_frame = GfxRandom[x][y];
442 }
443
444 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
445 {
446   /* animation synchronized with global frame counter, not move position */
447   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
448     sync_frame = FrameCounter;
449
450   return getAnimationFrame(graphic_info[graphic].anim_frames,
451                            graphic_info[graphic].anim_delay,
452                            graphic_info[graphic].anim_mode,
453                            graphic_info[graphic].anim_start_frame,
454                            sync_frame);
455 }
456
457 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
458                                     int graphic, int sync_frame, int mask_mode)
459 {
460   int frame = getGraphicAnimationFrame(graphic, sync_frame);
461
462   if (mask_mode == USE_MASKING)
463     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
464   else
465     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
466 }
467
468 inline void DrawGraphicAnimation(int x, int y, int graphic)
469 {
470   int lx = LEVELX(x), ly = LEVELY(y);
471
472   if (!IN_SCR_FIELD(x, y))
473     return;
474
475   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
476                           graphic, GfxFrame[lx][ly], NO_MASKING);
477   MarkTileDirty(x, y);
478 }
479
480 void DrawLevelGraphicAnimation(int x, int y, int graphic)
481 {
482   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
483 }
484
485 void DrawLevelElementAnimation(int x, int y, int element)
486 {
487 #if 1
488   int graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
489
490   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
491 #else
492   DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
493 #endif
494 }
495
496 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
497 {
498   int sx = SCREENX(x), sy = SCREENY(y);
499
500   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
501     return;
502
503   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
504     return;
505
506   DrawGraphicAnimation(sx, sy, graphic);
507 }
508
509 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
510 {
511   int sx = SCREENX(x), sy = SCREENY(y);
512   int graphic;
513
514   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
515     return;
516
517   graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
518
519   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
520     return;
521
522   DrawGraphicAnimation(sx, sy, graphic);
523 }
524
525 void DrawAllPlayers()
526 {
527   int i;
528
529   for(i=0; i<MAX_PLAYERS; i++)
530     if (stored_player[i].active)
531       DrawPlayer(&stored_player[i]);
532 }
533
534 void DrawPlayerField(int x, int y)
535 {
536   if (!IS_PLAYER(x, y))
537     return;
538
539   DrawPlayer(PLAYERINFO(x, y));
540 }
541
542 void DrawPlayer(struct PlayerInfo *player)
543 {
544 #if 0
545   int jx = player->jx, jy = player->jy;
546   int last_jx = player->last_jx, last_jy = player->last_jy;
547   int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
548   int sx = SCREENX(jx), sy = SCREENY(jy);
549   int sxx = 0, syy = 0;
550   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
551   int graphic;
552   int frame = 0;
553   boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
554   int move_dir = player->MovDir;
555   int action = ACTION_DEFAULT;
556 #else
557   int jx = player->jx, jy = player->jy;
558   int move_dir = player->MovDir;
559   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
560   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
561   int last_jx = (player->is_moving ? jx - dx : jx);
562   int last_jy = (player->is_moving ? jy - dy : jy);
563   int next_jx = jx + dx;
564   int next_jy = jy + dy;
565   int sx = SCREENX(jx), sy = SCREENY(jy);
566   int sxx = 0, syy = 0;
567   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
568   int graphic;
569   int frame = 0;
570   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
571   int action = ACTION_DEFAULT;
572 #endif
573
574   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
575     return;
576
577 #if DEBUG
578   if (!IN_LEV_FIELD(jx,jy))
579   {
580     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
581     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
582     printf("DrawPlayerField(): This should never happen!\n");
583     return;
584   }
585 #endif
586
587   if (element == EL_EXPLOSION)
588     return;
589
590   action = (player->Pushing ? ACTION_PUSHING :
591             player->is_digging ? ACTION_DIGGING :
592             player->is_collecting ? ACTION_COLLECTING :
593             player->is_moving ? ACTION_MOVING :
594             player->snapped ? ACTION_SNAPPING : ACTION_DEFAULT);
595
596   InitPlayerGfxAnimation(player, action, move_dir);
597
598   /* ----------------------------------------------------------------------- */
599   /* draw things in the field the player is leaving, if needed               */
600   /* ----------------------------------------------------------------------- */
601
602 #if 1
603   if (player->is_moving)
604 #else
605   if (player_is_moving)
606 #endif
607   {
608     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
609     {
610       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
611
612       if (last_element == EL_DYNAMITE_ACTIVE ||
613           last_element == EL_SP_DISK_RED_ACTIVE)
614         DrawDynamite(last_jx, last_jy);
615       else
616         DrawLevelFieldThruMask(last_jx, last_jy);
617     }
618     else if (last_element == EL_DYNAMITE_ACTIVE ||
619              last_element == EL_SP_DISK_RED_ACTIVE)
620       DrawDynamite(last_jx, last_jy);
621     else
622       DrawLevelField(last_jx, last_jy);
623
624     if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
625     {
626 #if 1
627 #if 1
628       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
629 #else
630       if (player->GfxPos)
631       {
632         if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
633           DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
634         else
635           DrawLevelElement(next_jx, next_jy, EL_EMPTY);
636       }
637       else
638         DrawLevelField(next_jx, next_jy);
639 #endif
640 #endif
641     }
642   }
643
644   if (!IN_SCR_FIELD(sx, sy))
645     return;
646
647   if (setup.direct_draw)
648     SetDrawtoField(DRAW_BUFFERED);
649
650   /* ----------------------------------------------------------------------- */
651   /* draw things behind the player, if needed                                */
652   /* ----------------------------------------------------------------------- */
653
654   if (Back[jx][jy])
655     DrawLevelElement(jx, jy, Back[jx][jy]);
656   else if (IS_ACTIVE_BOMB(element))
657     DrawLevelElement(jx, jy, EL_EMPTY);
658   else
659   {
660     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
661     {
662 #if 1
663       if (CAN_BE_CRUMBLED(GfxElement[jx][jy]))
664         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
665 #else
666       if (GfxElement[jx][jy] == EL_SAND)
667         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
668 #endif
669       else
670       {
671         int old_element = GfxElement[jx][jy];
672         int old_graphic = el_act_dir2img(old_element, action, move_dir);
673         int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
674
675         DrawGraphic(sx, sy, old_graphic, frame);
676       }
677     }
678     else
679     {
680       GfxElement[jx][jy] = EL_UNDEFINED;
681
682       DrawLevelField(jx, jy);
683     }
684   }
685
686   /* ----------------------------------------------------------------------- */
687   /* draw player himself                                                     */
688   /* ----------------------------------------------------------------------- */
689
690   if (player->use_murphy_graphic)
691   {
692     static int last_horizontal_dir = MV_LEFT;
693     int direction;
694
695     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
696       last_horizontal_dir = move_dir;
697
698     direction = (player->snapped ? move_dir : last_horizontal_dir);
699
700     graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
701   }
702   else
703     graphic = el_act_dir2img(player->element_nr, player->GfxAction, move_dir);
704
705   frame = getGraphicAnimationFrame(graphic, player->Frame);
706
707   if (player->GfxPos)
708   {
709     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
710       sxx = player->GfxPos;
711     else
712       syy = player->GfxPos;
713   }
714
715   if (!setup.soft_scrolling && ScreenMovPos)
716     sxx = syy = 0;
717
718   DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
719
720   if (SHIELD_ON(player))
721   {
722     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
723                    IMG_SHIELD_NORMAL_ACTIVE);
724     int frame = getGraphicAnimationFrame(graphic, -1);
725
726     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
727   }
728
729   /* ----------------------------------------------------------------------- */
730   /* draw things the player is pushing, if needed                            */
731   /* ----------------------------------------------------------------------- */
732
733 #if 0
734   printf("::: %d, %d [%d, %d] [%d]\n",
735          player->Pushing, player_is_moving, player->GfxAction,
736          player->is_moving, player_is_moving);
737 #endif
738
739 #if 1
740   if (player->Pushing && player->is_moving)
741 #else
742   if (player->Pushing && player_is_moving)
743 #endif
744   {
745     int px = SCREENX(next_jx), py = SCREENY(next_jy);
746
747     if (Back[next_jx][next_jy])
748       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
749
750 #if 1
751     if ((sxx || syy) && element == EL_SOKOBAN_OBJECT)
752       DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
753                                  NO_CUTTING);
754 #else
755     if ((sxx || syy) &&
756         (element == EL_SOKOBAN_FIELD_EMPTY ||
757          Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
758       DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
759                                  NO_CUTTING);
760 #endif
761     else
762     {
763 #if 1
764       int element = MovingOrBlocked2Element(next_jx, next_jy);
765 #else
766 #if 1
767       int element = Feld[jx][jy];
768 #else
769       int element = Feld[next_jx][next_jy];
770 #endif
771 #endif
772
773 #if 1
774       int graphic = el2img(element);
775       int frame = 0;
776
777 #if 0
778       if ((sxx || syy) && IS_PUSHABLE(element))
779 #endif
780       {
781         graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
782         frame = getGraphicAnimationFrame(graphic, player->Frame);
783       }
784
785 #if 0
786       printf("::: pushing %d: %d ...\n", sxx, frame);
787 #endif
788
789       DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
790                          NO_CUTTING, NO_MASKING);
791 #endif
792     }
793   }
794
795   /* ----------------------------------------------------------------------- */
796   /* draw things in front of player (active dynamite or dynabombs)           */
797   /* ----------------------------------------------------------------------- */
798
799   if (IS_ACTIVE_BOMB(element))
800   {
801     graphic = el2img(element);
802     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
803
804     if (game.emulation == EMU_SUPAPLEX)
805       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
806     else
807       DrawGraphicThruMask(sx, sy, graphic, frame);
808   }
809
810   if (player_is_moving && last_element == EL_EXPLOSION)
811   {
812 #if 1
813     int graphic = el_act2img(GfxElement[last_jx][last_jy], ACTION_EXPLODING);
814 #else
815     int stored = Store[last_jx][last_jy];
816     int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
817                    stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
818                    IMG_SP_EXPLOSION);
819 #endif
820     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
821     int phase = ExplodePhase[last_jx][last_jy] - 1;
822     int frame = getGraphicAnimationFrame(graphic, phase - delay);
823
824     if (phase >= delay)
825       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
826   }
827
828   /* ----------------------------------------------------------------------- */
829   /* draw elements the player is just walking/passing through/under          */
830   /* ----------------------------------------------------------------------- */
831
832   /* handle the field the player is leaving ... */
833   if (player_is_moving && IS_ACCESSIBLE_INSIDE(last_element))
834     DrawLevelField(last_jx, last_jy);
835   else if (player_is_moving && IS_ACCESSIBLE_UNDER(last_element))
836     DrawLevelFieldThruMask(last_jx, last_jy);
837
838   /* ... and the field the player is entering */
839   if (IS_ACCESSIBLE_INSIDE(element))
840     DrawLevelField(jx, jy);
841   else if (IS_ACCESSIBLE_UNDER(element))
842     DrawLevelFieldThruMask(jx, jy);
843
844   if (setup.direct_draw)
845   {
846     int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
847     int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
848     int x_size = TILEX * (1 + ABS(jx - last_jx));
849     int y_size = TILEY * (1 + ABS(jy - last_jy));
850
851     BlitBitmap(drawto_field, window,
852                dest_x, dest_y, x_size, y_size, dest_x, dest_y);
853     SetDrawtoField(DRAW_DIRECT);
854   }
855
856   MarkTileDirty(sx,sy);
857 }
858
859 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
860 {
861   struct GraphicInfo *g = &graphic_info[graphic];
862
863   *bitmap = g->bitmap;
864
865   if (g->offset_y == 0)         /* frames are ordered horizontally */
866   {
867     int max_width = g->anim_frames_per_line * g->width;
868
869     *x = (g->src_x + frame * g->offset_x) % max_width;
870     *y = g->src_y + (g->src_x + frame * g->offset_x) / max_width * g->height;
871   }
872   else if (g->offset_x == 0)    /* frames are ordered vertically */
873   {
874     int max_height = g->anim_frames_per_line * g->height;
875
876     *x = g->src_x + (g->src_y + frame * g->offset_y) / max_height * g->width;
877     *y = (g->src_y + frame * g->offset_y) % max_height;
878   }
879   else                          /* frames are ordered diagonally */
880   {
881     *x = g->src_x + frame * g->offset_x;
882     *y = g->src_y + frame * g->offset_y;
883   }
884 }
885
886 void DrawGraphic(int x, int y, int graphic, int frame)
887 {
888 #if DEBUG
889   if (!IN_SCR_FIELD(x, y))
890   {
891     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
892     printf("DrawGraphic(): This should never happen!\n");
893     return;
894   }
895 #endif
896
897   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
898   MarkTileDirty(x, y);
899 }
900
901 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
902                     int frame)
903 {
904   Bitmap *src_bitmap;
905   int src_x, src_y;
906
907   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
908   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
909 }
910
911 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
912 {
913 #if DEBUG
914   if (!IN_SCR_FIELD(x, y))
915   {
916     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
917     printf("DrawGraphicThruMask(): This should never happen!\n");
918     return;
919   }
920 #endif
921
922   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
923                          frame);
924   MarkTileDirty(x, y);
925 }
926
927 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
928                             int frame)
929 {
930 #if 1
931   Bitmap *src_bitmap;
932   int src_x, src_y;
933   GC drawing_gc;
934
935   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
936   drawing_gc = src_bitmap->stored_clip_gc;
937 #else
938   GC drawing_gc = src_bitmap->stored_clip_gc;
939   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
940   int src_x = graphic_info[graphic].src_x;
941   int src_y = graphic_info[graphic].src_y;
942   int offset_x = graphic_info[graphic].offset_x;
943   int offset_y = graphic_info[graphic].offset_y;
944
945   src_x += frame * offset_x;
946   src_y += frame * offset_y;
947
948 #endif
949
950   SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
951   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
952 }
953
954 void DrawMiniGraphic(int x, int y, int graphic)
955 {
956   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
957   MarkTileDirty(x / 2, y / 2);
958 }
959
960 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
961 {
962   struct GraphicInfo *g = &graphic_info[graphic];
963   int mini_startx = 0;
964   int mini_starty = g->bitmap->height * 2 / 3;
965
966   *bitmap = g->bitmap;
967   *x = mini_startx + g->src_x / 2;
968   *y = mini_starty + g->src_y / 2;
969 }
970
971 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
972 {
973   Bitmap *src_bitmap;
974   int src_x, src_y;
975
976   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
977   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
978 }
979
980 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
981                         int cut_mode, int mask_mode)
982 {
983   Bitmap *src_bitmap;
984   GC drawing_gc;
985   int src_x, src_y;
986   int width = TILEX, height = TILEY;
987   int cx = 0, cy = 0;
988   int dest_x, dest_y;
989
990   if (graphic < 0)
991   {
992     DrawGraphic(x, y, graphic, frame);
993     return;
994   }
995
996   if (dx || dy)                 /* shifted graphic */
997   {
998     if (x < BX1)                /* object enters playfield from the left */
999     {
1000       x = BX1;
1001       width = dx;
1002       cx = TILEX - dx;
1003       dx = 0;
1004     }
1005     else if (x > BX2)           /* object enters playfield from the right */
1006     {
1007       x = BX2;
1008       width = -dx;
1009       dx = TILEX + dx;
1010     }
1011     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1012     {
1013       width += dx;
1014       cx = -dx;
1015       dx = 0;
1016     }
1017     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1018       width -= dx;
1019     else if (dx)                /* general horizontal movement */
1020       MarkTileDirty(x + SIGN(dx), y);
1021
1022     if (y < BY1)                /* object enters playfield from the top */
1023     {
1024       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1025         return;
1026
1027       y = BY1;
1028       height = dy;
1029       cy = TILEY - dy;
1030       dy = 0;
1031     }
1032     else if (y > BY2)           /* object enters playfield from the bottom */
1033     {
1034       y = BY2;
1035       height = -dy;
1036       dy = TILEY + dy;
1037     }
1038     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1039     {
1040       height += dy;
1041       cy = -dy;
1042       dy = 0;
1043     }
1044     else if (dy > 0 && cut_mode == CUT_ABOVE)
1045     {
1046       if (y == BY2)             /* object completely above bottom border */
1047         return;
1048
1049       height = dy;
1050       cy = TILEY - dy;
1051       dy = TILEY;
1052       MarkTileDirty(x, y + 1);
1053     }                           /* object leaves playfield to the bottom */
1054     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1055       height -= dy;
1056     else if (dy)                /* general vertical movement */
1057       MarkTileDirty(x, y + SIGN(dy));
1058   }
1059
1060 #if 1
1061   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1062 #else
1063   src_bitmap = graphic_info[graphic].bitmap;
1064   src_x = graphic_info[graphic].src_x;
1065   src_y = graphic_info[graphic].src_y;
1066   offset_x = graphic_info[graphic].offset_x;
1067   offset_y = graphic_info[graphic].offset_y;
1068
1069   src_x += frame * offset_x;
1070   src_y += frame * offset_y;
1071 #endif
1072
1073   drawing_gc = src_bitmap->stored_clip_gc;
1074
1075   src_x += cx;
1076   src_y += cy;
1077
1078   dest_x = FX + x * TILEX + dx;
1079   dest_y = FY + y * TILEY + dy;
1080
1081 #if DEBUG
1082   if (!IN_SCR_FIELD(x,y))
1083   {
1084     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1085     printf("DrawGraphicShifted(): This should never happen!\n");
1086     return;
1087   }
1088 #endif
1089
1090   if (mask_mode == USE_MASKING)
1091   {
1092     SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1093     BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1094                      dest_x, dest_y);
1095   }
1096   else
1097     BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1098                dest_x, dest_y);
1099
1100   MarkTileDirty(x,y);
1101 }
1102
1103 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1104                                 int frame, int cut_mode)
1105 {
1106   DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1107 }
1108
1109 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1110                           int cut_mode, int mask_mode)
1111 {
1112   int lx = LEVELX(x), ly = LEVELY(y);
1113   int graphic;
1114   int frame;
1115
1116   if (IN_LEV_FIELD(lx, ly))
1117   {
1118     SetRandomAnimationValue(lx, ly);
1119
1120     graphic = el_act_dir2img(element, GfxAction[lx][ly], MovDir[lx][ly]);
1121     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1122   }
1123   else  /* border element */
1124   {
1125     graphic = el2img(element);
1126     frame = getGraphicAnimationFrame(graphic, -1);
1127   }
1128
1129   if (element == EL_EXPANDABLE_WALL)
1130   {
1131     boolean left_stopped = FALSE, right_stopped = FALSE;
1132
1133     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1134       left_stopped = TRUE;
1135     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1136       right_stopped = TRUE;
1137
1138     if (left_stopped && right_stopped)
1139       graphic = IMG_WALL;
1140     else if (left_stopped)
1141     {
1142       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1143       frame = graphic_info[graphic].anim_frames - 1;
1144     }
1145     else if (right_stopped)
1146     {
1147       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1148       frame = graphic_info[graphic].anim_frames - 1;
1149     }
1150   }
1151
1152   if (dx || dy)
1153     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1154   else if (mask_mode == USE_MASKING)
1155     DrawGraphicThruMask(x, y, graphic, frame);
1156   else
1157     DrawGraphic(x, y, graphic, frame);
1158 }
1159
1160 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1161                          int cut_mode, int mask_mode)
1162 {
1163   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1164     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1165                          cut_mode, mask_mode);
1166 }
1167
1168 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1169                               int cut_mode)
1170 {
1171   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1172 }
1173
1174 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1175                              int cut_mode)
1176 {
1177   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1178 }
1179
1180 void DrawLevelElementThruMask(int x, int y, int element)
1181 {
1182   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1183 }
1184
1185 void DrawLevelFieldThruMask(int x, int y)
1186 {
1187   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1188 }
1189
1190 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1191 {
1192   Bitmap *src_bitmap;
1193   int src_x, src_y;
1194   int sx = SCREENX(x), sy = SCREENY(y);
1195   int element;
1196   int width, height, cx, cy, i;
1197   int snip = TILEX / 8; /* number of border pixels from "crumbled graphic" */
1198   static int xy[4][2] =
1199   {
1200     { 0, -1 },
1201     { -1, 0 },
1202     { +1, 0 },
1203     { 0, +1 }
1204   };
1205
1206   if (!IN_LEV_FIELD(x, y))
1207     return;
1208
1209   element = (GfxElement[x][y] != EL_UNDEFINED && Feld[x][y] != EL_EXPLOSION ?
1210              GfxElement[x][y] : Feld[x][y]);
1211
1212   /* crumble field itself */
1213   if (CAN_BE_CRUMBLED(element) && !IS_MOVING(x, y))
1214   {
1215     if (!IN_SCR_FIELD(sx, sy))
1216       return;
1217
1218     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1219
1220     for(i=0; i<4; i++)
1221     {
1222       int xx = x + xy[i][0];
1223       int yy = y + xy[i][1];
1224
1225       element = (IN_LEV_FIELD(xx, yy) ? Feld[xx][yy] : BorderElement);
1226
1227       /* check if neighbour field is of same type */
1228       if (CAN_BE_CRUMBLED(element) && !IS_MOVING(xx, yy))
1229         continue;
1230
1231 #if 0
1232       if (Feld[x][y] == EL_CUSTOM_START + 123)
1233         printf("::: crumble [%d] THE CHAOS ENGINE (%d, %d): %d, %d\n",
1234                i, Feld[x][y], element,
1235                CAN_BE_CRUMBLED(element), IS_MOVING(x, y));
1236 #endif
1237
1238       if (i == 1 || i == 2)
1239       {
1240         width = snip;
1241         height = TILEY;
1242         cx = (i == 2 ? TILEX - snip : 0);
1243         cy = 0;
1244       }
1245       else
1246       {
1247         width = TILEX;
1248         height = snip;
1249         cx = 0;
1250         cy = (i == 3 ? TILEY - snip : 0);
1251       }
1252
1253       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1254                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1255     }
1256
1257     MarkTileDirty(sx, sy);
1258   }
1259   else          /* crumble neighbour fields */
1260   {
1261     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1262
1263     for(i=0; i<4; i++)
1264     {
1265       int xx = x + xy[i][0];
1266       int yy = y + xy[i][1];
1267       int sxx = sx + xy[i][0];
1268       int syy = sy + xy[i][1];
1269
1270       if (!IN_LEV_FIELD(xx, yy) ||
1271           !IN_SCR_FIELD(sxx, syy) ||
1272           !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1273           IS_MOVING(xx, yy))
1274         continue;
1275
1276       if (i == 1 || i == 2)
1277       {
1278         width = snip;
1279         height = TILEY;
1280         cx = (i == 1 ? TILEX - snip : 0);
1281         cy = 0;
1282       }
1283       else
1284       {
1285         width = TILEX;
1286         height = snip;
1287         cx = 0;
1288         cy = (i==0 ? TILEY-snip : 0);
1289       }
1290
1291       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1292                  width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1293
1294       MarkTileDirty(sxx, syy);
1295     }
1296   }
1297 }
1298
1299 void DrawLevelFieldCrumbledSand(int x, int y)
1300 {
1301   DrawLevelFieldCrumbledSandExt(x, y, IMG_SAND_CRUMBLED, 0);
1302 }
1303
1304 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1305                                        int step_frame)
1306 {
1307 #if 1
1308   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1309   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1310 #else
1311   int graphic1 = el_act_dir2img(EL_SAND,          ACTION_DIGGING, direction);
1312   int graphic2 = el_act_dir2img(EL_SAND_CRUMBLED, ACTION_DIGGING, direction);
1313 #endif
1314   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1315   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1316   int sx = SCREENX(x), sy = SCREENY(y);
1317
1318   DrawGraphic(sx, sy, graphic1, frame1);
1319   DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1320 }
1321
1322 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1323 {
1324   int sx = SCREENX(x), sy = SCREENY(y);
1325   static int xy[4][2] =
1326   {
1327     { 0, -1 },
1328     { -1, 0 },
1329     { +1, 0 },
1330     { 0, +1 }
1331   };
1332   int i;
1333
1334   for(i=0; i<4; i++)
1335   {
1336     int xx = x + xy[i][0];
1337     int yy = y + xy[i][1];
1338     int sxx = sx + xy[i][0];
1339     int syy = sy + xy[i][1];
1340
1341     if (!IN_LEV_FIELD(xx, yy) ||
1342         !IN_SCR_FIELD(sxx, syy) ||
1343         !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
1344         IS_MOVING(xx, yy))
1345       continue;
1346
1347     DrawLevelField(xx, yy);
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   DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(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_DROPPING)
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_DROPPING)
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   *bitmap = src_bitmap;
1527   *x = src_x;
1528   *y = src_y;
1529 }
1530
1531 void DrawMicroElement(int xpos, int ypos, int element)
1532 {
1533   Bitmap *src_bitmap;
1534   int src_x, src_y;
1535   int graphic = el2preimg(element);
1536
1537   getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1538   BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1539              xpos, ypos);
1540 }
1541
1542 void DrawLevel()
1543 {
1544   int x,y;
1545
1546   SetDrawBackgroundMask(REDRAW_NONE);
1547   ClearWindow();
1548
1549   for(x=BX1; x<=BX2; x++)
1550     for(y=BY1; y<=BY2; y++)
1551       DrawScreenField(x, y);
1552
1553   redraw_mask |= REDRAW_FIELD;
1554 }
1555
1556 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1557 {
1558   int x,y;
1559
1560   for(x=0; x<size_x; x++)
1561     for(y=0; y<size_y; y++)
1562       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1563
1564   redraw_mask |= REDRAW_FIELD;
1565 }
1566
1567 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1568 {
1569   int x, y;
1570
1571   DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1572
1573   if (lev_fieldx < STD_LEV_FIELDX)
1574     xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1575   if (lev_fieldy < STD_LEV_FIELDY)
1576     ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1577
1578   xpos += MICRO_TILEX;
1579   ypos += MICRO_TILEY;
1580
1581   for(x=-1; x<=STD_LEV_FIELDX; x++)
1582   {
1583     for(y=-1; y<=STD_LEV_FIELDY; y++)
1584     {
1585       int lx = from_x + x, ly = from_y + y;
1586
1587       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1588         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1589                          level.field[lx][ly]);
1590       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1591                && BorderElement != EL_EMPTY)
1592         DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1593                          getBorderElement(lx, ly));
1594     }
1595   }
1596
1597   redraw_mask |= REDRAW_MICROLEVEL;
1598 }
1599
1600 #define MICROLABEL_EMPTY                0
1601 #define MICROLABEL_LEVEL_NAME           1
1602 #define MICROLABEL_CREATED_BY           2
1603 #define MICROLABEL_LEVEL_AUTHOR         3
1604 #define MICROLABEL_IMPORTED_FROM        4
1605 #define MICROLABEL_LEVEL_IMPORT_INFO    5
1606
1607 static void DrawMicroLevelLabelExt(int mode)
1608 {
1609   char label_text[MAX_OUTPUT_LINESIZE + 1];
1610   int max_len_label_text;
1611   int font_nr = FONT_TEXT_2;
1612
1613   if (mode == MICROLABEL_CREATED_BY || mode == MICROLABEL_IMPORTED_FROM)
1614     font_nr = FONT_TEXT_3;
1615
1616   max_len_label_text = SXSIZE / getFontWidth(font_nr);
1617
1618   DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, getFontHeight(font_nr));
1619
1620   strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1621                        mode == MICROLABEL_CREATED_BY ? "created by" :
1622                        mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1623                        mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1624                        mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1625                        leveldir_current->imported_from : ""),
1626           max_len_label_text);
1627   label_text[max_len_label_text] = '\0';
1628
1629   if (strlen(label_text) > 0)
1630   {
1631     int text_width = strlen(label_text) * getFontWidth(font_nr);
1632     int lxpos = SX + (SXSIZE - text_width) / 2;
1633     int lypos = MICROLABEL_YPOS;
1634
1635     DrawText(lxpos, lypos, label_text, font_nr);
1636   }
1637
1638   redraw_mask |= REDRAW_MICROLEVEL;
1639 }
1640
1641 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1642 {
1643   static unsigned long scroll_delay = 0;
1644   static unsigned long label_delay = 0;
1645   static int from_x, from_y, scroll_direction;
1646   static int label_state, label_counter;
1647   int last_game_status = game_status;   /* save current game status */
1648
1649   /* force PREVIEW font on preview level */
1650   game_status = GAME_MODE_PSEUDO_PREVIEW;
1651
1652   if (restart)
1653   {
1654     from_x = from_y = 0;
1655     scroll_direction = MV_RIGHT;
1656     label_state = 1;
1657     label_counter = 0;
1658
1659     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1660     DrawMicroLevelLabelExt(label_state);
1661
1662     /* initialize delay counters */
1663     DelayReached(&scroll_delay, 0);
1664     DelayReached(&label_delay, 0);
1665
1666     if (leveldir_current->name)
1667     {
1668       int len = strlen(leveldir_current->name);
1669       int lxpos = SX + (SXSIZE - len * getFontWidth(FONT_TEXT_1)) / 2;
1670       int lypos = SY + 352;
1671
1672       DrawText(lxpos, lypos, leveldir_current->name, FONT_TEXT_1);
1673     }
1674
1675     game_status = last_game_status;     /* restore current game status */
1676
1677     return;
1678   }
1679
1680   /* scroll micro level, if needed */
1681   if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1682       DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1683   {
1684     switch (scroll_direction)
1685     {
1686       case MV_LEFT:
1687         if (from_x > 0)
1688           from_x--;
1689         else
1690           scroll_direction = MV_UP;
1691         break;
1692
1693       case MV_RIGHT:
1694         if (from_x < lev_fieldx - STD_LEV_FIELDX)
1695           from_x++;
1696         else
1697           scroll_direction = MV_DOWN;
1698         break;
1699
1700       case MV_UP:
1701         if (from_y > 0)
1702           from_y--;
1703         else
1704           scroll_direction = MV_RIGHT;
1705         break;
1706
1707       case MV_DOWN:
1708         if (from_y < lev_fieldy - STD_LEV_FIELDY)
1709           from_y++;
1710         else
1711           scroll_direction = MV_LEFT;
1712         break;
1713
1714       default:
1715         break;
1716     }
1717
1718     DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1719   }
1720
1721   /* redraw micro level label, if needed */
1722   if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1723       strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1724       strcmp(level.author, leveldir_current->name) != 0 &&
1725       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1726   {
1727     int max_label_counter = 23;
1728
1729     if (leveldir_current->imported_from != NULL)
1730       max_label_counter += 14;
1731
1732     label_counter = (label_counter + 1) % max_label_counter;
1733     label_state = (label_counter >= 0 && label_counter <= 7 ?
1734                    MICROLABEL_LEVEL_NAME :
1735                    label_counter >= 9 && label_counter <= 12 ?
1736                    MICROLABEL_CREATED_BY :
1737                    label_counter >= 14 && label_counter <= 21 ?
1738                    MICROLABEL_LEVEL_AUTHOR :
1739                    label_counter >= 23 && label_counter <= 26 ?
1740                    MICROLABEL_IMPORTED_FROM :
1741                    label_counter >= 28 && label_counter <= 35 ?
1742                    MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1743     DrawMicroLevelLabelExt(label_state);
1744   }
1745
1746   game_status = last_game_status;       /* restore current game status */
1747 }
1748
1749 int REQ_in_range(int x, int y)
1750 {
1751   if (y > DY+249 && y < DY+278)
1752   {
1753     if (x > DX+1 && x < DX+48)
1754       return 1;
1755     else if (x > DX+51 && x < DX+98) 
1756       return 2;
1757   }
1758   return 0;
1759 }
1760
1761 #define MAX_REQUEST_LINES               13
1762 #define MAX_REQUEST_LINE_LEN            7
1763
1764 boolean Request(char *text, unsigned int req_state)
1765 {
1766   int mx, my, ty, result = -1;
1767   unsigned int old_door_state;
1768   int last_game_status = game_status;   /* save current game status */
1769
1770 #if defined(PLATFORM_UNIX)
1771   /* pause network game while waiting for request to answer */
1772   if (options.network &&
1773       game_status == GAME_MODE_PLAYING &&
1774       req_state & REQUEST_WAIT_FOR)
1775     SendToServer_PausePlaying();
1776 #endif
1777
1778   old_door_state = GetDoorState();
1779
1780   /* simulate releasing mouse button over last gadget, if still pressed */
1781   if (button_status)
1782     HandleGadgets(-1, -1, 0);
1783
1784   UnmapAllGadgets();
1785
1786   CloseDoor(DOOR_CLOSE_1);
1787
1788   /* save old door content */
1789   BlitBitmap(bitmap_db_door, bitmap_db_door,
1790              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1791              DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1792
1793   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1794
1795   /* clear door drawing field */
1796   DrawBackground(DX, DY, DXSIZE, DYSIZE);
1797
1798   /* force DOOR font on preview level */
1799   game_status = GAME_MODE_PSEUDO_DOOR;
1800
1801   /* write text for request */
1802   for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1803   {
1804     char text_line[MAX_REQUEST_LINE_LEN + 1];
1805     int tx, tl, tc;
1806
1807     if (!*text)
1808       break;
1809
1810     for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1811     {
1812       tc = *(text + tx);
1813       if (!tc || tc == ' ')
1814         break;
1815     }
1816
1817     if (!tl)
1818     { 
1819       text++; 
1820       ty--; 
1821       continue; 
1822     }
1823
1824     strncpy(text_line, text, tl);
1825     text_line[tl] = 0;
1826
1827     DrawText(DX + (DXSIZE - tl * getFontWidth(FONT_TEXT_2)) / 2,
1828              DY + 8 + ty * (getFontHeight(FONT_TEXT_2) + 2),
1829              text_line, FONT_TEXT_2);
1830
1831     text += tl + (tc == ' ' ? 1 : 0);
1832   }
1833
1834   game_status = last_game_status;       /* restore current game status */
1835
1836   if (req_state & REQ_ASK)
1837   {
1838     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1839     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1840   }
1841   else if (req_state & REQ_CONFIRM)
1842   {
1843     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1844   }
1845   else if (req_state & REQ_PLAYER)
1846   {
1847     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1848     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1849     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1850     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1851   }
1852
1853   /* copy request gadgets to door backbuffer */
1854   BlitBitmap(drawto, bitmap_db_door,
1855              DX, DY, DXSIZE, DYSIZE,
1856              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1857
1858   OpenDoor(DOOR_OPEN_1);
1859
1860 #if 0
1861   ClearEventQueue();
1862 #endif
1863
1864   if (!(req_state & REQUEST_WAIT_FOR))
1865   {
1866     SetDrawBackgroundMask(REDRAW_FIELD);
1867
1868     return FALSE;
1869   }
1870
1871   if (game_status != GAME_MODE_MAIN)
1872     InitAnimation();
1873
1874   button_status = MB_RELEASED;
1875
1876   request_gadget_id = -1;
1877
1878   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1879
1880   while(result < 0)
1881   {
1882     if (PendingEvent())
1883     {
1884       Event event;
1885
1886       NextEvent(&event);
1887
1888       switch(event.type)
1889       {
1890         case EVENT_BUTTONPRESS:
1891         case EVENT_BUTTONRELEASE:
1892         case EVENT_MOTIONNOTIFY:
1893         {
1894           if (event.type == EVENT_MOTIONNOTIFY)
1895           {
1896             if (!PointerInWindow(window))
1897               continue; /* window and pointer are on different screens */
1898
1899             if (!button_status)
1900               continue;
1901
1902             motion_status = TRUE;
1903             mx = ((MotionEvent *) &event)->x;
1904             my = ((MotionEvent *) &event)->y;
1905           }
1906           else
1907           {
1908             motion_status = FALSE;
1909             mx = ((ButtonEvent *) &event)->x;
1910             my = ((ButtonEvent *) &event)->y;
1911             if (event.type == EVENT_BUTTONPRESS)
1912               button_status = ((ButtonEvent *) &event)->button;
1913             else
1914               button_status = MB_RELEASED;
1915           }
1916
1917           /* this sets 'request_gadget_id' */
1918           HandleGadgets(mx, my, button_status);
1919
1920           switch(request_gadget_id)
1921           {
1922             case TOOL_CTRL_ID_YES:
1923               result = TRUE;
1924               break;
1925             case TOOL_CTRL_ID_NO:
1926               result = FALSE;
1927               break;
1928             case TOOL_CTRL_ID_CONFIRM:
1929               result = TRUE | FALSE;
1930               break;
1931
1932             case TOOL_CTRL_ID_PLAYER_1:
1933               result = 1;
1934               break;
1935             case TOOL_CTRL_ID_PLAYER_2:
1936               result = 2;
1937               break;
1938             case TOOL_CTRL_ID_PLAYER_3:
1939               result = 3;
1940               break;
1941             case TOOL_CTRL_ID_PLAYER_4:
1942               result = 4;
1943               break;
1944
1945             default:
1946               break;
1947           }
1948
1949           break;
1950         }
1951
1952         case EVENT_KEYPRESS:
1953           switch(GetEventKey((KeyEvent *)&event, TRUE))
1954           {
1955             case KSYM_Return:
1956               result = 1;
1957               break;
1958
1959             case KSYM_Escape:
1960               result = 0;
1961               break;
1962
1963             default:
1964               break;
1965           }
1966           if (req_state & REQ_PLAYER)
1967             result = 0;
1968           break;
1969
1970         case EVENT_KEYRELEASE:
1971           ClearPlayerAction();
1972           break;
1973
1974         default:
1975           HandleOtherEvents(&event);
1976           break;
1977       }
1978     }
1979     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1980     {
1981       int joy = AnyJoystick();
1982
1983       if (joy & JOY_BUTTON_1)
1984         result = 1;
1985       else if (joy & JOY_BUTTON_2)
1986         result = 0;
1987     }
1988
1989     DoAnimation();
1990
1991     /* don't eat all CPU time */
1992     Delay(10);
1993   }
1994
1995   if (game_status != GAME_MODE_MAIN)
1996     StopAnimation();
1997
1998   UnmapToolButtons();
1999
2000   if (!(req_state & REQ_STAY_OPEN))
2001   {
2002     CloseDoor(DOOR_CLOSE_1);
2003
2004     if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2005     {
2006       BlitBitmap(bitmap_db_door, bitmap_db_door,
2007                  DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2008                  DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2009       OpenDoor(DOOR_OPEN_1);
2010     }
2011   }
2012
2013   RemapAllGadgets();
2014
2015   SetDrawBackgroundMask(REDRAW_FIELD);
2016
2017 #if defined(PLATFORM_UNIX)
2018   /* continue network game after request */
2019   if (options.network &&
2020       game_status == GAME_MODE_PLAYING &&
2021       req_state & REQUEST_WAIT_FOR)
2022     SendToServer_ContinuePlaying();
2023 #endif
2024
2025   return result;
2026 }
2027
2028 unsigned int OpenDoor(unsigned int door_state)
2029 {
2030   unsigned int new_door_state;
2031
2032   if (door_state & DOOR_COPY_BACK)
2033   {
2034     BlitBitmap(bitmap_db_door, bitmap_db_door,
2035                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2036                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2037     door_state &= ~DOOR_COPY_BACK;
2038   }
2039
2040   new_door_state = MoveDoor(door_state);
2041
2042   return(new_door_state);
2043 }
2044
2045 unsigned int CloseDoor(unsigned int door_state)
2046 {
2047   unsigned int new_door_state;
2048
2049   BlitBitmap(backbuffer, bitmap_db_door,
2050              DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2051   BlitBitmap(backbuffer, bitmap_db_door,
2052              VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2053
2054   new_door_state = MoveDoor(door_state);
2055
2056   return(new_door_state);
2057 }
2058
2059 unsigned int GetDoorState()
2060 {
2061   return MoveDoor(DOOR_GET_STATE);
2062 }
2063
2064 unsigned int SetDoorState(unsigned int door_state)
2065 {
2066   return MoveDoor(door_state | DOOR_SET_STATE);
2067 }
2068
2069 unsigned int MoveDoor(unsigned int door_state)
2070 {
2071   static int door1 = DOOR_OPEN_1;
2072   static int door2 = DOOR_CLOSE_2;
2073   static unsigned long door_delay = 0;
2074   int x, start, stepsize = door.step_offset;
2075   unsigned long door_delay_value = door.step_delay;
2076
2077   if (door_state == DOOR_GET_STATE)
2078     return(door1 | door2);
2079
2080   if (door_state & DOOR_SET_STATE)
2081   {
2082     if (door_state & DOOR_ACTION_1)
2083       door1 = door_state & DOOR_ACTION_1;
2084     if (door_state & DOOR_ACTION_2)
2085       door2 = door_state & DOOR_ACTION_2;
2086
2087     return(door1 | door2);
2088   }
2089
2090   if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2091     door_state &= ~DOOR_OPEN_1;
2092   else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2093     door_state &= ~DOOR_CLOSE_1;
2094   if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2095     door_state &= ~DOOR_OPEN_2;
2096   else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2097     door_state &= ~DOOR_CLOSE_2;
2098
2099   if (setup.quick_doors)
2100   {
2101     stepsize = 20;
2102     door_delay_value = 0;
2103
2104     StopSound(SND_DOOR_OPENING);
2105     StopSound(SND_DOOR_CLOSING);
2106   }
2107
2108   if (global.autoplay_leveldir)
2109   {
2110     door_state |= DOOR_NO_DELAY;
2111     door_state &= ~DOOR_CLOSE_ALL;
2112   }
2113
2114   if (door_state & DOOR_ACTION)
2115   {
2116     if (!(door_state & DOOR_NO_DELAY))
2117     {
2118       /* opening door sound has priority over simultaneously closing door */
2119       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2120         PlaySoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2121       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2122         PlaySoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2123     }
2124
2125     start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2126
2127     for(x=start; x<=DXSIZE; x+=stepsize)
2128     {
2129       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2130       GC gc = bitmap->stored_clip_gc;
2131
2132       if (!(door_state & DOOR_NO_DELAY))
2133         WaitUntilDelayReached(&door_delay, door_delay_value);
2134
2135       if (door_state & DOOR_ACTION_1)
2136       {
2137         int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2138         int j = (DXSIZE - i) / 3;
2139
2140         BlitBitmap(bitmap_db_door, drawto,
2141                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2142                    DXSIZE,DYSIZE - i/2, DX, DY);
2143
2144         ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2145
2146         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2147         BlitBitmapMasked(bitmap, drawto,
2148                          DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2149                          DX + DXSIZE - i, DY + j);
2150         BlitBitmapMasked(bitmap, drawto,
2151                          DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2152                          DX + DXSIZE - i, DY + 140 + j);
2153         SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2154         BlitBitmapMasked(bitmap, drawto,
2155                          DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2156                          DX, DY);
2157         BlitBitmapMasked(bitmap, drawto,
2158                          DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2159                          DX, DY + 140 - j);
2160
2161         BlitBitmapMasked(bitmap, drawto,
2162                          DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2163                          DX, DY + 77 - j);
2164         BlitBitmapMasked(bitmap, drawto,
2165                          DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2166                          DX, DY + 203 - j);
2167         SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2168         BlitBitmapMasked(bitmap, drawto,
2169                          DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2170                          DX + DXSIZE - i, DY + 77 + j);
2171         BlitBitmapMasked(bitmap, drawto,
2172                          DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2173                          DX + DXSIZE - i, DY + 203 + j);
2174
2175         redraw_mask |= REDRAW_DOOR_1;
2176       }
2177
2178       if (door_state & DOOR_ACTION_2)
2179       {
2180         int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2181         int j = (VXSIZE - i) / 3;
2182
2183         BlitBitmap(bitmap_db_door, drawto,
2184                    DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2185                    VXSIZE, VYSIZE - i/2, VX, VY);
2186
2187         ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2188
2189         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2190         BlitBitmapMasked(bitmap, drawto,
2191                          VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2192                          VX + VXSIZE-i, VY+j);
2193         SetClipOrigin(bitmap, gc,
2194                       VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2195         BlitBitmapMasked(bitmap, drawto,
2196                          VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2197                          VX, VY);
2198
2199         BlitBitmapMasked(bitmap, drawto,
2200                          VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2201                          i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2202         SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2203         BlitBitmapMasked(bitmap, drawto,
2204                          VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2205                          i, VYSIZE / 2 - j,
2206                          VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2207
2208         redraw_mask |= REDRAW_DOOR_2;
2209       }
2210
2211       BackToFront();
2212
2213       if (game_status == GAME_MODE_MAIN)
2214         DoAnimation();
2215     }
2216   }
2217
2218   if (setup.quick_doors)
2219   {
2220     StopSound(SND_DOOR_OPENING);
2221     StopSound(SND_DOOR_CLOSING);
2222   }
2223
2224   if (door_state & DOOR_ACTION_1)
2225     door1 = door_state & DOOR_ACTION_1;
2226   if (door_state & DOOR_ACTION_2)
2227     door2 = door_state & DOOR_ACTION_2;
2228
2229   return (door1 | door2);
2230 }
2231
2232 void DrawSpecialEditorDoor()
2233 {
2234   /* draw bigger toolbox window */
2235   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2236              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2237              EX - 4, EY - 12);
2238   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2239              EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2240              EX - 4, EY - 4);
2241
2242   redraw_mask |= REDRAW_ALL;
2243 }
2244
2245 void UndrawSpecialEditorDoor()
2246 {
2247   /* draw normal tape recorder window */
2248   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2249              EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2250              EX - 4, EY - 12);
2251
2252   redraw_mask |= REDRAW_ALL;
2253 }
2254
2255
2256 /* ---------- new tool button stuff ---------------------------------------- */
2257
2258 /* graphic position values for tool buttons */
2259 #define TOOL_BUTTON_YES_XPOS            2
2260 #define TOOL_BUTTON_YES_YPOS            250
2261 #define TOOL_BUTTON_YES_GFX_YPOS        0
2262 #define TOOL_BUTTON_YES_XSIZE           46
2263 #define TOOL_BUTTON_YES_YSIZE           28
2264 #define TOOL_BUTTON_NO_XPOS             52
2265 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
2266 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
2267 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
2268 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
2269 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
2270 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
2271 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
2272 #define TOOL_BUTTON_CONFIRM_XSIZE       96
2273 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
2274 #define TOOL_BUTTON_PLAYER_XSIZE        30
2275 #define TOOL_BUTTON_PLAYER_YSIZE        30
2276 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
2277 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
2278 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2279 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2280 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2281                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2282 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2283                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2284 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2285                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2286 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
2287                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2288 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2289                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2290 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2291                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2292 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2293                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2294 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
2295                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2296
2297 static struct
2298 {
2299   int xpos, ypos;
2300   int x, y;
2301   int width, height;
2302   int gadget_id;
2303   char *infotext;
2304 } toolbutton_info[NUM_TOOL_BUTTONS] =
2305 {
2306   {
2307     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
2308     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
2309     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
2310     TOOL_CTRL_ID_YES,
2311     "yes"
2312   },
2313   {
2314     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
2315     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
2316     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
2317     TOOL_CTRL_ID_NO,
2318     "no"
2319   },
2320   {
2321     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
2322     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
2323     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
2324     TOOL_CTRL_ID_CONFIRM,
2325     "confirm"
2326   },
2327   {
2328     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2329     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
2330     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2331     TOOL_CTRL_ID_PLAYER_1,
2332     "player 1"
2333   },
2334   {
2335     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2336     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
2337     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2338     TOOL_CTRL_ID_PLAYER_2,
2339     "player 2"
2340   },
2341   {
2342     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2343     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
2344     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2345     TOOL_CTRL_ID_PLAYER_3,
2346     "player 3"
2347   },
2348   {
2349     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2350     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
2351     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
2352     TOOL_CTRL_ID_PLAYER_4,
2353     "player 4"
2354   }
2355 };
2356
2357 void CreateToolButtons()
2358 {
2359   int i;
2360
2361   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2362   {
2363     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2364     Bitmap *deco_bitmap = None;
2365     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2366     struct GadgetInfo *gi;
2367     unsigned long event_mask;
2368     int gd_xoffset, gd_yoffset;
2369     int gd_x1, gd_x2, gd_y;
2370     int id = i;
2371
2372     event_mask = GD_EVENT_RELEASED;
2373
2374     gd_xoffset = toolbutton_info[i].xpos;
2375     gd_yoffset = toolbutton_info[i].ypos;
2376     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2377     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2378     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2379
2380     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2381     {
2382       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2383
2384       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
2385                            &deco_bitmap, &deco_x, &deco_y);
2386       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2387       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2388     }
2389
2390     gi = CreateGadget(GDI_CUSTOM_ID, id,
2391                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
2392                       GDI_X, DX + toolbutton_info[i].x,
2393                       GDI_Y, DY + toolbutton_info[i].y,
2394                       GDI_WIDTH, toolbutton_info[i].width,
2395                       GDI_HEIGHT, toolbutton_info[i].height,
2396                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2397                       GDI_STATE, GD_BUTTON_UNPRESSED,
2398                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2399                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2400                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2401                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2402                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2403                       GDI_DECORATION_SHIFTING, 1, 1,
2404                       GDI_EVENT_MASK, event_mask,
2405                       GDI_CALLBACK_ACTION, HandleToolButtons,
2406                       GDI_END);
2407
2408     if (gi == NULL)
2409       Error(ERR_EXIT, "cannot create gadget");
2410
2411     tool_gadget[id] = gi;
2412   }
2413 }
2414
2415 void FreeToolButtons()
2416 {
2417   int i;
2418
2419   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2420     FreeGadget(tool_gadget[i]);
2421 }
2422
2423 static void UnmapToolButtons()
2424 {
2425   int i;
2426
2427   for (i=0; i<NUM_TOOL_BUTTONS; i++)
2428     UnmapGadget(tool_gadget[i]);
2429 }
2430
2431 static void HandleToolButtons(struct GadgetInfo *gi)
2432 {
2433   request_gadget_id = gi->custom_id;
2434 }
2435
2436 int get_next_element(int element)
2437 {
2438   switch(element)
2439   {
2440     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
2441     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
2442     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
2443     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
2444     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
2445     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
2446     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
2447
2448     default:                            return element;
2449   }
2450 }
2451
2452 int el_act_dir2img(int element, int action, int direction)
2453 {
2454   element = GFX_ELEMENT(element);
2455   direction = MV_DIR_BIT(direction);
2456
2457   return element_info[element].direction_graphic[action][direction];
2458 }
2459
2460 static int el_act_dir2crm(int element, int action, int direction)
2461 {
2462   element = GFX_ELEMENT(element);
2463   direction = MV_DIR_BIT(direction);
2464
2465   return element_info[element].direction_crumbled[action][direction];
2466 }
2467
2468 int el_act2img(int element, int action)
2469 {
2470   element = GFX_ELEMENT(element);
2471
2472   return element_info[element].graphic[action];
2473 }
2474
2475 int el_dir2img(int element, int direction)
2476 {
2477   element = GFX_ELEMENT(element);
2478
2479   return el_act_dir2img(element, ACTION_DEFAULT, direction);
2480 }
2481
2482 int el2img(int element)
2483 {
2484   element = GFX_ELEMENT(element);
2485
2486   return element_info[element].graphic[ACTION_DEFAULT];
2487 }
2488
2489 int el2edimg(int element)
2490 {
2491   element = GFX_ELEMENT(element);
2492
2493   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
2494 }
2495
2496 int el2preimg(int element)
2497 {
2498   element = GFX_ELEMENT(element);
2499
2500   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
2501 }