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