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