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