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