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