rnd-20070405-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 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 #include "screens.h"
23
24
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX    0
27
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES        0
30 #define TOOL_CTRL_ID_NO         1
31 #define TOOL_CTRL_ID_CONFIRM    2
32 #define TOOL_CTRL_ID_PLAYER_1   3
33 #define TOOL_CTRL_ID_PLAYER_2   4
34 #define TOOL_CTRL_ID_PLAYER_3   5
35 #define TOOL_CTRL_ID_PLAYER_4   6
36
37 #define NUM_TOOL_BUTTONS        7
38
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
44
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
47
48 static char *print_if_not_empty(int element)
49 {
50   static char *s = NULL;
51   char *token_name = element_info[element].token_name;
52
53   if (s != NULL)
54     free(s);
55
56   s = checked_malloc(strlen(token_name) + 10 + 1);
57
58   if (element != EL_EMPTY)
59     sprintf(s, "%d\t['%s']", element, token_name);
60   else
61     sprintf(s, "%d", element);
62
63   return s;
64 }
65
66 void DumpTile(int x, int y)
67 {
68   int sx = SCREENX(x);
69   int sy = SCREENY(y);
70
71   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
72   {
73     x--;
74     y--;
75   }
76
77   printf_line("-", 79);
78   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
79   printf_line("-", 79);
80
81   if (!IN_LEV_FIELD(x, y))
82   {
83     printf("(not in level field)\n");
84     printf("\n");
85
86     return;
87   }
88
89   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
90          element_info[Feld[x][y]].token_name);
91   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
92   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
93   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
94   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95   printf("  MovPos:      %d\n", MovPos[x][y]);
96   printf("  MovDir:      %d\n", MovDir[x][y]);
97   printf("  MovDelay:    %d\n", MovDelay[x][y]);
98   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
99   printf("  CustomValue: %d\n", CustomValue[x][y]);
100   printf("  GfxElement:  %d\n", GfxElement[x][y]);
101   printf("  GfxAction:   %d\n", GfxAction[x][y]);
102   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
103   printf("\n");
104 }
105
106 void SetDrawtoField(int mode)
107 {
108   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
109   {
110     FX = TILEX;
111     FY = TILEY;
112     BX1 = -1;
113     BY1 = -1;
114     BX2 = SCR_FIELDX;
115     BY2 = SCR_FIELDY;
116     redraw_x1 = 1;
117     redraw_y1 = 1;
118
119     drawto_field = fieldbuffer;
120   }
121   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
122   {
123     FX = SX;
124     FY = SY;
125     BX1 = 0;
126     BY1 = 0;
127     BX2 = SCR_FIELDX - 1;
128     BY2 = SCR_FIELDY - 1;
129     redraw_x1 = 0;
130     redraw_y1 = 0;
131
132     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
133   }
134 }
135
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 {
138   if (game_status == GAME_MODE_PLAYING &&
139       level.game_engine_type == GAME_ENGINE_TYPE_EM)
140   {
141     /* currently there is no partial redraw -- always redraw whole playfield */
142     RedrawPlayfield_EM(TRUE);
143
144     /* blit playfield from scroll buffer to normal back buffer for fading in */
145     BlitScreenToBitmap_EM(backbuffer);
146   }
147   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
148   {
149     if (force_redraw)
150     {
151       x = gfx.sx - TILEX;
152       y = gfx.sy - TILEY;
153       width = gfx.sxsize + 2 * TILEX;
154       height = gfx.sysize + 2 * TILEY;
155     }
156
157     if (force_redraw || setup.direct_draw)
158     {
159       int xx, yy;
160       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162
163       if (setup.direct_draw)
164         SetDrawtoField(DRAW_BACKBUFFER);
165
166       for (xx = BX1; xx <= BX2; xx++)
167         for (yy = BY1; yy <= BY2; yy++)
168           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169             DrawScreenField(xx, yy);
170       DrawAllPlayers();
171
172       if (setup.direct_draw)
173         SetDrawtoField(DRAW_DIRECT);
174     }
175
176     if (setup.soft_scrolling)
177     {
178       int fx = FX, fy = FY;
179
180       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
182
183       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184     }
185   }
186
187   if (force_redraw)
188   {
189     x = gfx.sx;
190     y = gfx.sy;
191     width = gfx.sxsize;
192     height = gfx.sysize;
193   }
194
195   BlitBitmap(drawto, window, x, y, width, height, x, y);
196 }
197
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 {
200   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201
202   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
204 }
205
206 void DrawMaskedBorder_FIELD()
207 {
208   if (game_status >= GAME_MODE_TITLE &&
209       game_status <= GAME_MODE_PLAYING &&
210       border.draw_masked[game_status])
211     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
212 }
213
214 void DrawMaskedBorder_DOOR_1()
215 {
216   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217       (game_status != GAME_MODE_EDITOR ||
218        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
220 }
221
222 void DrawMaskedBorder_DOOR_2()
223 {
224   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225       game_status != GAME_MODE_EDITOR)
226     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
227 }
228
229 void DrawMaskedBorder_DOOR_3()
230 {
231   /* currently not available */
232 }
233
234 void DrawMaskedBorder_ALL()
235 {
236   DrawMaskedBorder_FIELD();
237   DrawMaskedBorder_DOOR_1();
238   DrawMaskedBorder_DOOR_2();
239   DrawMaskedBorder_DOOR_3();
240 }
241
242 void DrawMaskedBorder(int redraw_mask)
243 {
244   /* do not draw masked screen borders when displaying title screens */
245   if (effectiveGameStatus() == GAME_MODE_TITLE)
246     return;
247
248   if (redraw_mask & REDRAW_ALL)
249     DrawMaskedBorder_ALL();
250   else
251   {
252     if (redraw_mask & REDRAW_FIELD)
253       DrawMaskedBorder_FIELD();
254     if (redraw_mask & REDRAW_DOOR_1)
255       DrawMaskedBorder_DOOR_1();
256     if (redraw_mask & REDRAW_DOOR_2)
257       DrawMaskedBorder_DOOR_2();
258     if (redraw_mask & REDRAW_DOOR_3)
259       DrawMaskedBorder_DOOR_3();
260   }
261 }
262
263 void BackToFront()
264 {
265   int x,y;
266   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
267
268   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
269     redraw_mask &= ~REDRAW_MAIN;
270
271   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
272     redraw_mask |= REDRAW_FIELD;
273
274   if (redraw_mask & REDRAW_FIELD)
275     redraw_mask &= ~REDRAW_TILES;
276
277   if (redraw_mask == REDRAW_NONE)
278     return;
279
280   if (redraw_mask & REDRAW_TILES &&
281       game_status == GAME_MODE_PLAYING &&
282       border.draw_masked[GAME_MODE_PLAYING])
283     redraw_mask |= REDRAW_FIELD;
284
285   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
286   {
287     static boolean last_frame_skipped = FALSE;
288     boolean skip_even_when_not_scrolling = TRUE;
289     boolean just_scrolling = (ScreenMovDir != 0);
290     boolean verbose = FALSE;
291
292     if (global.fps_slowdown_factor > 1 &&
293         (FrameCounter % global.fps_slowdown_factor) &&
294         (just_scrolling || skip_even_when_not_scrolling))
295     {
296       redraw_mask &= ~REDRAW_MAIN;
297
298       last_frame_skipped = TRUE;
299
300       if (verbose)
301         printf("FRAME SKIPPED\n");
302     }
303     else
304     {
305       if (last_frame_skipped)
306         redraw_mask |= REDRAW_FIELD;
307
308       last_frame_skipped = FALSE;
309
310       if (verbose)
311         printf("frame not skipped\n");
312     }
313   }
314
315   /* synchronize X11 graphics at this point; if we would synchronize the
316      display immediately after the buffer switching (after the XFlush),
317      this could mean that we have to wait for the graphics to complete,
318      although we could go on doing calculations for the next frame */
319
320   SyncDisplay();
321
322   /* prevent drawing masked border to backbuffer when using playfield buffer */
323   if (game_status != GAME_MODE_PLAYING ||
324       redraw_mask & REDRAW_FROM_BACKBUFFER ||
325       buffer == backbuffer)
326     DrawMaskedBorder(redraw_mask);
327   else
328     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
329
330   if (redraw_mask & REDRAW_ALL)
331   {
332     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
333
334     redraw_mask = REDRAW_NONE;
335   }
336
337   if (redraw_mask & REDRAW_FIELD)
338   {
339     if (game_status != GAME_MODE_PLAYING ||
340         redraw_mask & REDRAW_FROM_BACKBUFFER)
341     {
342       BlitBitmap(backbuffer, window,
343                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
344     }
345     else
346     {
347       int fx = FX, fy = FY;
348
349       if (setup.soft_scrolling)
350       {
351         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
352         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
353       }
354
355       if (setup.soft_scrolling ||
356           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
357           ABS(ScreenMovPos) == ScrollStepSize ||
358           redraw_tiles > REDRAWTILES_THRESHOLD)
359       {
360         if (border.draw_masked[GAME_MODE_PLAYING])
361         {
362           if (buffer != backbuffer)
363           {
364             /* copy playfield buffer to backbuffer to add masked border */
365             BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
366             DrawMaskedBorder(REDRAW_FIELD);
367           }
368
369           BlitBitmap(backbuffer, window,
370                      REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
371                      REAL_SX, REAL_SY);
372         }
373         else
374         {
375           BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
376         }
377
378 #if 0
379 #ifdef DEBUG
380         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
381                ScreenGfxPos,
382                (setup.soft_scrolling ?
383                 "setup.soft_scrolling" :
384                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
385                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
386                 ABS(ScreenGfxPos) == ScrollStepSize ?
387                 "ABS(ScreenGfxPos) == ScrollStepSize" :
388                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
389 #endif
390 #endif
391       }
392     }
393
394     redraw_mask &= ~REDRAW_MAIN;
395   }
396
397   if (redraw_mask & REDRAW_DOORS)
398   {
399     if (redraw_mask & REDRAW_DOOR_1)
400       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
401
402     if (redraw_mask & REDRAW_DOOR_2)
403       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
404
405     if (redraw_mask & REDRAW_DOOR_3)
406       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
407
408     redraw_mask &= ~REDRAW_DOORS;
409   }
410
411   if (redraw_mask & REDRAW_MICROLEVEL)
412   {
413     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
414                SX, SY + 10 * TILEY);
415
416     redraw_mask &= ~REDRAW_MICROLEVEL;
417   }
418
419   if (redraw_mask & REDRAW_TILES)
420   {
421     for (x = 0; x < SCR_FIELDX; x++)
422       for (y = 0 ; y < SCR_FIELDY; y++)
423         if (redraw[redraw_x1 + x][redraw_y1 + y])
424           BlitBitmap(buffer, window,
425                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
426                      SX + x * TILEX, SY + y * TILEY);
427   }
428
429   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
430   {
431     char text[100];
432     char info1[100];
433
434     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
435     if (!global.fps_slowdown)
436       info1[0] = '\0';
437
438     sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
439     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
440   }
441
442   FlushDisplay();
443
444   for (x = 0; x < MAX_BUF_XSIZE; x++)
445     for (y = 0; y < MAX_BUF_YSIZE; y++)
446       redraw[x][y] = 0;
447   redraw_tiles = 0;
448   redraw_mask = REDRAW_NONE;
449 }
450
451 void FadeToFront()
452 {
453 #if 0
454   long fading_delay = 300;
455
456   if (setup.fading && (redraw_mask & REDRAW_FIELD))
457   {
458 #endif
459
460 #if 0
461     int x,y;
462
463     ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
464     FlushDisplay();
465
466     for (i = 0; i < 2 * FULL_SYSIZE; i++)
467     {
468       for (y = 0; y < FULL_SYSIZE; y++)
469       {
470         BlitBitmap(backbuffer, window,
471                    REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
472       }
473       FlushDisplay();
474       Delay(10);
475     }
476 #endif
477
478 #if 0
479     for (i = 1; i < FULL_SYSIZE; i+=2)
480       BlitBitmap(backbuffer, window,
481                  REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
482     FlushDisplay();
483     Delay(fading_delay);
484 #endif
485
486 #if 0
487     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
488     BlitBitmapMasked(backbuffer, window,
489                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
490                      REAL_SX,REAL_SY);
491     FlushDisplay();
492     Delay(fading_delay);
493
494     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
495     BlitBitmapMasked(backbuffer, window,
496                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
497                      REAL_SX,REAL_SY);
498     FlushDisplay();
499     Delay(fading_delay);
500
501     SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
502     BlitBitmapMasked(backbuffer, window,
503                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
504                      REAL_SX,REAL_SY);
505     FlushDisplay();
506     Delay(fading_delay);
507
508     SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
509     BlitBitmapMasked(backbuffer, window,
510                      REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
511                      REAL_SX,REAL_SY);
512     FlushDisplay();
513     Delay(fading_delay);
514
515     redraw_mask &= ~REDRAW_MAIN;
516   }
517 #endif
518
519   BackToFront();
520 }
521
522 void FadeExt(int fade_mask, int fade_mode)
523 {
524   static int fade_mode_skip = FADE_MODE_NONE;
525   void (*draw_border_function)(void) = NULL;
526 #if 0
527   Bitmap *bitmap = (fade_mode != FADE_MODE_FADE_IN ? bitmap_db_cross : NULL);
528 #else
529   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
530 #endif
531   int x, y, width, height;
532   int fade_delay, post_delay;
533
534   redraw_mask |= fade_mask;
535
536   if (fade_mode & FADE_TYPE_SKIP)
537   {
538 #if 0
539     printf("::: will skip %d ... [%d]\n", fade_mode, fade_mode_skip);
540 #endif
541
542     fade_mode_skip = fade_mode;
543
544     return;
545   }
546
547   if (fade_mode_skip & FADE_TYPE_SKIP)
548   {
549 #if 0
550     printf("::: skipping %d ... [%d]\n", fade_mode, fade_mode_skip);
551 #endif
552
553     /* skip all fade operations until specified fade operation */
554     if (fade_mode & fade_mode_skip)
555       fade_mode_skip = FADE_MODE_NONE;
556
557     return;
558   }
559
560 #if 1
561   if (global.autoplay_leveldir)
562   {
563     // fading.fade_mode = FADE_MODE_NONE;
564
565     return;
566   }
567 #endif
568
569 #if 1
570   if (fading.fade_mode == FADE_MODE_NONE)
571   {
572     BackToFront();
573
574     return;
575   }
576 #endif
577
578   if (fade_mask & REDRAW_FIELD)
579   {
580     x = REAL_SX;
581     y = REAL_SY;
582     width  = FULL_SXSIZE;
583     height = FULL_SYSIZE;
584
585     fade_delay = fading.fade_delay;
586     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
587
588     draw_border_function = DrawMaskedBorder_FIELD;
589   }
590   else          /* REDRAW_ALL */
591   {
592     x = 0;
593     y = 0;
594     width  = WIN_XSIZE;
595     height = WIN_YSIZE;
596
597     fade_delay = fading.fade_delay;
598     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
599   }
600
601 #if 1
602   if (!setup.fade_screens || fade_delay == 0)
603 #else
604   if (!setup.fade_screens || fade_delay == 0 || fading.anim_mode == ANIM_NONE)
605 #endif
606   {
607     if (fade_mode == FADE_MODE_FADE_OUT)
608       ClearRectangle(backbuffer, x, y, width, height);
609
610     BackToFront();
611
612     return;
613   }
614
615   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
616                 draw_border_function);
617
618   redraw_mask &= ~fade_mask;
619 }
620
621 void FadeIn(int fade_mask)
622 {
623 #if 1
624   // printf("::: now fading in...\n");
625
626   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
627     FadeExt(fade_mask, fading.fade_mode);
628   else
629     FadeExt(fade_mask, FADE_MODE_FADE_IN);
630 #else
631 #if 1
632   if (fading.fade_mode == FADE_MODE_CROSSFADE)
633     FadeExt(fade_mask, FADE_MODE_CROSSFADE);
634   else
635     FadeExt(fade_mask, FADE_MODE_FADE_IN);
636 #else
637   FadeExt(fade_mask, FADE_MODE_FADE_IN);
638 #endif
639 #endif
640 }
641
642 void FadeOut(int fade_mask)
643 {
644 #if 1
645   // printf("::: fading.fade_mode == %d\n", fading.fade_mode);
646
647   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
648     FadeCrossSaveBackbuffer();
649   else
650     FadeExt(fade_mask, FADE_MODE_FADE_OUT);
651 #else
652 #if 1
653   if (fading.fade_mode == FADE_MODE_CROSSFADE)
654     FadeCrossSaveBackbuffer();
655   else
656     FadeExt(fade_mask, FADE_MODE_FADE_OUT);
657 #else
658   FadeExt(fade_mask, FADE_MODE_FADE_OUT);
659 #endif
660 #endif
661 }
662
663 void FadeCross(int fade_mask)
664 {
665   FadeExt(fade_mask, FADE_MODE_CROSSFADE);
666 }
667
668 void FadeCrossSaveBackbuffer()
669 {
670   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
671 }
672
673 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
674 {
675   static struct TitleFadingInfo fading_leave_stored;
676
677   if (set)
678     fading_leave_stored = fading_leave;
679   else
680     fading = fading_leave_stored;
681 }
682
683 void FadeSetEnterMenu()
684 {
685   fading = menu.enter_menu;
686
687   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
688 }
689
690 void FadeSetLeaveMenu()
691 {
692   fading = menu.leave_menu;
693
694   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
695 }
696
697 void FadeSetEnterScreen()
698 {
699   fading = menu.enter_screen[game_status];
700
701   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
702 }
703
704 void FadeSetLeaveScreen()
705 {
706   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
707 }
708
709 void FadeSetFromType(int type)
710 {
711   if (type & TYPE_ENTER_SCREEN)
712     FadeSetEnterScreen();
713   else if (type & TYPE_ENTER)
714     FadeSetEnterMenu();
715   else if (type & TYPE_LEAVE)
716     FadeSetLeaveMenu();
717 }
718
719 void FadeSetDisabled()
720 {
721   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
722
723   fading = fading_none;
724 }
725
726 void FadeSkipNextFadeIn()
727 {
728   FadeExt(0, FADE_MODE_SKIP_FADE_IN);
729 }
730
731 void FadeSkipNextFadeOut()
732 {
733   FadeExt(0, FADE_MODE_SKIP_FADE_OUT);
734 }
735
736 void SetWindowBackgroundImageIfDefined(int graphic)
737 {
738   if (graphic_info[graphic].bitmap)
739     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
740 }
741
742 void SetMainBackgroundImageIfDefined(int graphic)
743 {
744   if (graphic_info[graphic].bitmap)
745     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
746 }
747
748 void SetDoorBackgroundImageIfDefined(int graphic)
749 {
750   if (graphic_info[graphic].bitmap)
751     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
752 }
753
754 void SetWindowBackgroundImage(int graphic)
755 {
756   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
757                             graphic_info[graphic].bitmap ?
758                             graphic_info[graphic].bitmap :
759                             graphic_info[IMG_BACKGROUND].bitmap);
760 }
761
762 void SetMainBackgroundImage(int graphic)
763 {
764   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
765                           graphic_info[graphic].bitmap ?
766                           graphic_info[graphic].bitmap :
767                           graphic_info[IMG_BACKGROUND].bitmap);
768 }
769
770 void SetDoorBackgroundImage(int graphic)
771 {
772   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
773                           graphic_info[graphic].bitmap ?
774                           graphic_info[graphic].bitmap :
775                           graphic_info[IMG_BACKGROUND].bitmap);
776 }
777
778 void SetPanelBackground()
779 {
780   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
781              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
782
783   SetDoorBackgroundBitmap(bitmap_db_panel);
784 }
785
786 void DrawBackground(int x, int y, int width, int height)
787 {
788   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
789   /* (when entering hall of fame after playing) */
790 #if 0
791   ClearRectangleOnBackground(drawto, x, y, width, height);
792 #else
793   ClearRectangleOnBackground(backbuffer, x, y, width, height);
794 #endif
795
796   redraw_mask |= REDRAW_FIELD;
797 }
798
799 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
800 {
801   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
802
803   if (font->bitmap == NULL)
804     return;
805
806   DrawBackground(x, y, width, height);
807 }
808
809 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
810 {
811   struct GraphicInfo *g = &graphic_info[graphic];
812
813   if (g->bitmap == NULL)
814     return;
815
816   DrawBackground(x, y, width, height);
817 }
818
819 void ClearWindow()
820 {
821   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
822   /* (when entering hall of fame after playing) */
823   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
824
825   /* !!! maybe this should be done before clearing the background !!! */
826   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
827   {
828     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
829     SetDrawtoField(DRAW_BUFFERED);
830   }
831   else
832     SetDrawtoField(DRAW_BACKBUFFER);
833
834   if (setup.direct_draw && game_status == GAME_MODE_PLAYING)
835   {
836     ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
837     SetDrawtoField(DRAW_DIRECT);
838   }
839 }
840
841 void MarkTileDirty(int x, int y)
842 {
843   int xx = redraw_x1 + x;
844   int yy = redraw_y1 + y;
845
846   if (!redraw[xx][yy])
847     redraw_tiles++;
848
849   redraw[xx][yy] = TRUE;
850   redraw_mask |= REDRAW_TILES;
851 }
852
853 void SetBorderElement()
854 {
855   int x, y;
856
857   BorderElement = EL_EMPTY;
858
859   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
860   {
861     for (x = 0; x < lev_fieldx; x++)
862     {
863       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
864         BorderElement = EL_STEELWALL;
865
866       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
867         x = lev_fieldx - 2;
868     }
869   }
870 }
871
872 void FloodFillLevel(int from_x, int from_y, int fill_element,
873                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
874                     int max_fieldx, int max_fieldy)
875 {
876   int i,x,y;
877   int old_element;
878   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
879   static int safety = 0;
880
881   /* check if starting field still has the desired content */
882   if (field[from_x][from_y] == fill_element)
883     return;
884
885   safety++;
886
887   if (safety > max_fieldx * max_fieldy)
888     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
889
890   old_element = field[from_x][from_y];
891   field[from_x][from_y] = fill_element;
892
893   for (i = 0; i < 4; i++)
894   {
895     x = from_x + check[i][0];
896     y = from_y + check[i][1];
897
898     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
899       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
900   }
901
902   safety--;
903 }
904
905 void SetRandomAnimationValue(int x, int y)
906 {
907   gfx.anim_random_frame = GfxRandom[x][y];
908 }
909
910 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
911 {
912   /* animation synchronized with global frame counter, not move position */
913   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
914     sync_frame = FrameCounter;
915
916   return getAnimationFrame(graphic_info[graphic].anim_frames,
917                            graphic_info[graphic].anim_delay,
918                            graphic_info[graphic].anim_mode,
919                            graphic_info[graphic].anim_start_frame,
920                            sync_frame);
921 }
922
923 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
924                            Bitmap **bitmap, int *x, int *y)
925 {
926   struct
927   {
928     int width_mult, width_div;
929     int height_mult, height_div;
930   }
931   offset_calc[6] =
932   {
933     { 15, 16,   2, 3    },      /* 1 x 1 */
934     { 7, 8,     2, 3    },      /* 2 x 2 */
935     { 3, 4,     2, 3    },      /* 4 x 4 */
936     { 1, 2,     2, 3    },      /* 8 x 8 */
937     { 0, 1,     2, 3    },      /* 16 x 16 */
938     { 0, 1,     0, 1    },      /* 32 x 32 */
939   };
940   struct GraphicInfo *g = &graphic_info[graphic];
941   Bitmap *src_bitmap = g->bitmap;
942   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
943   int offset_calc_pos = log_2(tilesize);
944   int width_mult  = offset_calc[offset_calc_pos].width_mult;
945   int width_div   = offset_calc[offset_calc_pos].width_div;
946   int height_mult = offset_calc[offset_calc_pos].height_mult;
947   int height_div  = offset_calc[offset_calc_pos].height_div;
948   int startx = src_bitmap->width * width_mult / width_div;
949   int starty = src_bitmap->height * height_mult / height_div;
950   int src_x = g->src_x * tilesize / TILESIZE;
951   int src_y = g->src_y * tilesize / TILESIZE;
952   int width = g->width * tilesize / TILESIZE;
953   int height = g->height * tilesize / TILESIZE;
954   int offset_x = g->offset_x * tilesize / TILESIZE;
955   int offset_y = g->offset_y * tilesize / TILESIZE;
956
957   if (g->offset_y == 0)         /* frames are ordered horizontally */
958   {
959     int max_width = g->anim_frames_per_line * width;
960     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
961
962     src_x = pos % max_width;
963     src_y = src_y % height + pos / max_width * height;
964   }
965   else if (g->offset_x == 0)    /* frames are ordered vertically */
966   {
967     int max_height = g->anim_frames_per_line * height;
968     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
969
970     src_x = src_x % width + pos / max_height * width;
971     src_y = pos % max_height;
972   }
973   else                          /* frames are ordered diagonally */
974   {
975     src_x = src_x + frame * offset_x;
976     src_y = src_y + frame * offset_y;
977   }
978
979   *bitmap = src_bitmap;
980   *x = startx + src_x;
981   *y = starty + src_y;
982 }
983
984 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
985 {
986 #if 1
987   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
988 #else
989   struct GraphicInfo *g = &graphic_info[graphic];
990   int mini_startx = 0;
991   int mini_starty = g->bitmap->height * 2 / 3;
992
993   *bitmap = g->bitmap;
994   *x = mini_startx + g->src_x / 2;
995   *y = mini_starty + g->src_y / 2;
996 #endif
997 }
998
999 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1000                                 int *x, int *y, boolean get_backside)
1001 {
1002   struct GraphicInfo *g = &graphic_info[graphic];
1003   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1004   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1005
1006   *bitmap = g->bitmap;
1007
1008   if (g->offset_y == 0)         /* frames are ordered horizontally */
1009   {
1010     int max_width = g->anim_frames_per_line * g->width;
1011     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1012
1013     *x = pos % max_width;
1014     *y = src_y % g->height + pos / max_width * g->height;
1015   }
1016   else if (g->offset_x == 0)    /* frames are ordered vertically */
1017   {
1018     int max_height = g->anim_frames_per_line * g->height;
1019     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1020
1021     *x = src_x % g->width + pos / max_height * g->width;
1022     *y = pos % max_height;
1023   }
1024   else                          /* frames are ordered diagonally */
1025   {
1026     *x = src_x + frame * g->offset_x;
1027     *y = src_y + frame * g->offset_y;
1028   }
1029 }
1030
1031 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1032 {
1033   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1034 }
1035
1036 void DrawGraphic(int x, int y, int graphic, int frame)
1037 {
1038 #if DEBUG
1039   if (!IN_SCR_FIELD(x, y))
1040   {
1041     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1042     printf("DrawGraphic(): This should never happen!\n");
1043     return;
1044   }
1045 #endif
1046
1047   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1048   MarkTileDirty(x, y);
1049 }
1050
1051 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1052                     int frame)
1053 {
1054   Bitmap *src_bitmap;
1055   int src_x, src_y;
1056
1057   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1058   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1059 }
1060
1061 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1062 {
1063 #if DEBUG
1064   if (!IN_SCR_FIELD(x, y))
1065   {
1066     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1067     printf("DrawGraphicThruMask(): This should never happen!\n");
1068     return;
1069   }
1070 #endif
1071
1072   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1073                          frame);
1074   MarkTileDirty(x, y);
1075 }
1076
1077 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1078                             int frame)
1079 {
1080   Bitmap *src_bitmap;
1081   int src_x, src_y;
1082
1083   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1084
1085   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1086                 dst_x - src_x, dst_y - src_y);
1087   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1088 }
1089
1090 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1091 {
1092   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1093                       frame, tilesize);
1094   MarkTileDirty(x / tilesize, y / tilesize);
1095 }
1096
1097 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1098                          int tilesize)
1099 {
1100   Bitmap *src_bitmap;
1101   int src_x, src_y;
1102
1103   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1104   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1105 }
1106
1107 void DrawMiniGraphic(int x, int y, int graphic)
1108 {
1109   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1110   MarkTileDirty(x / 2, y / 2);
1111 }
1112
1113 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1114 {
1115   Bitmap *src_bitmap;
1116   int src_x, src_y;
1117
1118   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1119   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1120 }
1121
1122 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1123                                             int graphic, int frame,
1124                                             int cut_mode, int mask_mode)
1125 {
1126   Bitmap *src_bitmap;
1127   int src_x, src_y;
1128   int dst_x, dst_y;
1129   int width = TILEX, height = TILEY;
1130   int cx = 0, cy = 0;
1131
1132   if (dx || dy)                 /* shifted graphic */
1133   {
1134     if (x < BX1)                /* object enters playfield from the left */
1135     {
1136       x = BX1;
1137       width = dx;
1138       cx = TILEX - dx;
1139       dx = 0;
1140     }
1141     else if (x > BX2)           /* object enters playfield from the right */
1142     {
1143       x = BX2;
1144       width = -dx;
1145       dx = TILEX + dx;
1146     }
1147     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1148     {
1149       width += dx;
1150       cx = -dx;
1151       dx = 0;
1152     }
1153     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1154       width -= dx;
1155     else if (dx)                /* general horizontal movement */
1156       MarkTileDirty(x + SIGN(dx), y);
1157
1158     if (y < BY1)                /* object enters playfield from the top */
1159     {
1160       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1161         return;
1162
1163       y = BY1;
1164       height = dy;
1165       cy = TILEY - dy;
1166       dy = 0;
1167     }
1168     else if (y > BY2)           /* object enters playfield from the bottom */
1169     {
1170       y = BY2;
1171       height = -dy;
1172       dy = TILEY + dy;
1173     }
1174     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1175     {
1176       height += dy;
1177       cy = -dy;
1178       dy = 0;
1179     }
1180     else if (dy > 0 && cut_mode == CUT_ABOVE)
1181     {
1182       if (y == BY2)             /* object completely above bottom border */
1183         return;
1184
1185       height = dy;
1186       cy = TILEY - dy;
1187       dy = TILEY;
1188       MarkTileDirty(x, y + 1);
1189     }                           /* object leaves playfield to the bottom */
1190     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1191       height -= dy;
1192     else if (dy)                /* general vertical movement */
1193       MarkTileDirty(x, y + SIGN(dy));
1194   }
1195
1196 #if DEBUG
1197   if (!IN_SCR_FIELD(x, y))
1198   {
1199     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1200     printf("DrawGraphicShifted(): This should never happen!\n");
1201     return;
1202   }
1203 #endif
1204
1205   if (width > 0 && height > 0)
1206   {
1207     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1208
1209     src_x += cx;
1210     src_y += cy;
1211
1212     dst_x = FX + x * TILEX + dx;
1213     dst_y = FY + y * TILEY + dy;
1214
1215     if (mask_mode == USE_MASKING)
1216     {
1217       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1218                     dst_x - src_x, dst_y - src_y);
1219       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1220                        dst_x, dst_y);
1221     }
1222     else
1223       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1224                  dst_x, dst_y);
1225
1226     MarkTileDirty(x, y);
1227   }
1228 }
1229
1230 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1231                                             int graphic, int frame,
1232                                             int cut_mode, int mask_mode)
1233 {
1234   Bitmap *src_bitmap;
1235   int src_x, src_y;
1236   int dst_x, dst_y;
1237   int width = TILEX, height = TILEY;
1238   int x1 = x;
1239   int y1 = y;
1240   int x2 = x + SIGN(dx);
1241   int y2 = y + SIGN(dy);
1242   int anim_frames = graphic_info[graphic].anim_frames;
1243   int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1244   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1245   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1246
1247   /* re-calculate animation frame for two-tile movement animation */
1248   frame = getGraphicAnimationFrame(graphic, sync_frame);
1249
1250   /* check if movement start graphic inside screen area and should be drawn */
1251   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1252   {
1253     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1254
1255     dst_x = FX + x1 * TILEX;
1256     dst_y = FY + y1 * TILEY;
1257
1258     if (mask_mode == USE_MASKING)
1259     {
1260       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1261                     dst_x - src_x, dst_y - src_y);
1262       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1263                        dst_x, dst_y);
1264     }
1265     else
1266       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1267                  dst_x, dst_y);
1268
1269     MarkTileDirty(x1, y1);
1270   }
1271
1272   /* check if movement end graphic inside screen area and should be drawn */
1273   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1274   {
1275     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1276
1277     dst_x = FX + x2 * TILEX;
1278     dst_y = FY + y2 * TILEY;
1279
1280     if (mask_mode == USE_MASKING)
1281     {
1282       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1283                     dst_x - src_x, dst_y - src_y);
1284       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1285                        dst_x, dst_y);
1286     }
1287     else
1288       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1289                  dst_x, dst_y);
1290
1291     MarkTileDirty(x2, y2);
1292   }
1293 }
1294
1295 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1296                                int graphic, int frame,
1297                                int cut_mode, int mask_mode)
1298 {
1299   if (graphic < 0)
1300   {
1301     DrawGraphic(x, y, graphic, frame);
1302
1303     return;
1304   }
1305
1306   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1307     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1308   else
1309     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1310 }
1311
1312 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1313                                 int frame, int cut_mode)
1314 {
1315   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1316 }
1317
1318 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1319                           int cut_mode, int mask_mode)
1320 {
1321   int lx = LEVELX(x), ly = LEVELY(y);
1322   int graphic;
1323   int frame;
1324
1325   if (IN_LEV_FIELD(lx, ly))
1326   {
1327     SetRandomAnimationValue(lx, ly);
1328
1329     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1330     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1331
1332     /* do not use double (EM style) movement graphic when not moving */
1333     if (graphic_info[graphic].double_movement && !dx && !dy)
1334     {
1335       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1336       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1337     }
1338   }
1339   else  /* border element */
1340   {
1341     graphic = el2img(element);
1342     frame = getGraphicAnimationFrame(graphic, -1);
1343   }
1344
1345   if (element == EL_EXPANDABLE_WALL)
1346   {
1347     boolean left_stopped = FALSE, right_stopped = FALSE;
1348
1349     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1350       left_stopped = TRUE;
1351     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1352       right_stopped = TRUE;
1353
1354     if (left_stopped && right_stopped)
1355       graphic = IMG_WALL;
1356     else if (left_stopped)
1357     {
1358       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1359       frame = graphic_info[graphic].anim_frames - 1;
1360     }
1361     else if (right_stopped)
1362     {
1363       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1364       frame = graphic_info[graphic].anim_frames - 1;
1365     }
1366   }
1367
1368   if (dx || dy)
1369     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1370   else if (mask_mode == USE_MASKING)
1371     DrawGraphicThruMask(x, y, graphic, frame);
1372   else
1373     DrawGraphic(x, y, graphic, frame);
1374 }
1375
1376 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1377                          int cut_mode, int mask_mode)
1378 {
1379   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1380     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1381                          cut_mode, mask_mode);
1382 }
1383
1384 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1385                               int cut_mode)
1386 {
1387   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1388 }
1389
1390 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1391                              int cut_mode)
1392 {
1393   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1394 }
1395
1396 void DrawLevelElementThruMask(int x, int y, int element)
1397 {
1398   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1399 }
1400
1401 void DrawLevelFieldThruMask(int x, int y)
1402 {
1403   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1404 }
1405
1406 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1407 {
1408   Bitmap *src_bitmap;
1409   int src_x, src_y;
1410   int sx = SCREENX(x), sy = SCREENY(y);
1411   int element;
1412   int width, height, cx, cy, i;
1413   int crumbled_border_size = graphic_info[graphic].border_size;
1414   static int xy[4][2] =
1415   {
1416     { 0, -1 },
1417     { -1, 0 },
1418     { +1, 0 },
1419     { 0, +1 }
1420   };
1421
1422   if (!IN_LEV_FIELD(x, y))
1423     return;
1424
1425   element = TILE_GFX_ELEMENT(x, y);
1426
1427   /* crumble field itself */
1428   if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1429   {
1430     if (!IN_SCR_FIELD(sx, sy))
1431       return;
1432
1433     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1434
1435     for (i = 0; i < 4; i++)
1436     {
1437       int xx = x + xy[i][0];
1438       int yy = y + xy[i][1];
1439
1440       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1441                  BorderElement);
1442
1443       /* check if neighbour field is of same type */
1444       if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1445         continue;
1446
1447       if (i == 1 || i == 2)
1448       {
1449         width = crumbled_border_size;
1450         height = TILEY;
1451         cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1452         cy = 0;
1453       }
1454       else
1455       {
1456         width = TILEX;
1457         height = crumbled_border_size;
1458         cx = 0;
1459         cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1460       }
1461
1462       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1463                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1464     }
1465
1466     MarkTileDirty(sx, sy);
1467   }
1468   else          /* crumble neighbour fields */
1469   {
1470     for (i = 0; i < 4; i++)
1471     {
1472       int xx = x + xy[i][0];
1473       int yy = y + xy[i][1];
1474       int sxx = sx + xy[i][0];
1475       int syy = sy + xy[i][1];
1476
1477       if (!IN_LEV_FIELD(xx, yy) ||
1478           !IN_SCR_FIELD(sxx, syy) ||
1479           IS_MOVING(xx, yy))
1480         continue;
1481
1482       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1483         continue;
1484
1485       element = TILE_GFX_ELEMENT(xx, yy);
1486
1487       if (!GFX_CRUMBLED(element))
1488         continue;
1489
1490       graphic = el_act2crm(element, ACTION_DEFAULT);
1491       crumbled_border_size = graphic_info[graphic].border_size;
1492
1493       getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1494
1495       if (i == 1 || i == 2)
1496       {
1497         width = crumbled_border_size;
1498         height = TILEY;
1499         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1500         cy = 0;
1501       }
1502       else
1503       {
1504         width = TILEX;
1505         height = crumbled_border_size;
1506         cx = 0;
1507         cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1508       }
1509
1510       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1511                  width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1512
1513       MarkTileDirty(sxx, syy);
1514     }
1515   }
1516 }
1517
1518 void DrawLevelFieldCrumbledSand(int x, int y)
1519 {
1520   int graphic;
1521
1522   if (!IN_LEV_FIELD(x, y))
1523     return;
1524
1525 #if 1
1526   /* !!! CHECK THIS !!! */
1527
1528   /*
1529   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1530       GFX_CRUMBLED(GfxElement[x][y]))
1531   */
1532
1533   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1534       GfxElement[x][y] != EL_UNDEFINED &&
1535       GFX_CRUMBLED(GfxElement[x][y]))
1536   {
1537     DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1538
1539     return;
1540   }
1541 #endif
1542
1543 #if 1
1544   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1545 #else
1546   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1547 #endif
1548
1549   DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1550 }
1551
1552 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1553                                        int step_frame)
1554 {
1555   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1556   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1557   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1558   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1559   int sx = SCREENX(x), sy = SCREENY(y);
1560
1561   DrawGraphic(sx, sy, graphic1, frame1);
1562   DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1563 }
1564
1565 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1566 {
1567   int sx = SCREENX(x), sy = SCREENY(y);
1568   static int xy[4][2] =
1569   {
1570     { 0, -1 },
1571     { -1, 0 },
1572     { +1, 0 },
1573     { 0, +1 }
1574   };
1575   int i;
1576
1577   for (i = 0; i < 4; i++)
1578   {
1579     int xx = x + xy[i][0];
1580     int yy = y + xy[i][1];
1581     int sxx = sx + xy[i][0];
1582     int syy = sy + xy[i][1];
1583
1584     if (!IN_LEV_FIELD(xx, yy) ||
1585         !IN_SCR_FIELD(sxx, syy) ||
1586         !GFX_CRUMBLED(Feld[xx][yy]) ||
1587         IS_MOVING(xx, yy))
1588       continue;
1589
1590     DrawLevelField(xx, yy);
1591   }
1592 }
1593
1594 static int getBorderElement(int x, int y)
1595 {
1596   int border[7][2] =
1597   {
1598     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
1599     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
1600     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1601     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1602     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
1603     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
1604     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
1605   };
1606   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1607   int steel_position = (x == -1         && y == -1              ? 0 :
1608                         x == lev_fieldx && y == -1              ? 1 :
1609                         x == -1         && y == lev_fieldy      ? 2 :
1610                         x == lev_fieldx && y == lev_fieldy      ? 3 :
1611                         x == -1         || x == lev_fieldx      ? 4 :
1612                         y == -1         || y == lev_fieldy      ? 5 : 6);
1613
1614   return border[steel_position][steel_type];
1615 }
1616
1617 void DrawScreenElement(int x, int y, int element)
1618 {
1619   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1620   DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1621 }
1622
1623 void DrawLevelElement(int x, int y, int element)
1624 {
1625   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1626     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1627 }
1628
1629 void DrawScreenField(int x, int y)
1630 {
1631   int lx = LEVELX(x), ly = LEVELY(y);
1632   int element, content;
1633
1634   if (!IN_LEV_FIELD(lx, ly))
1635   {
1636     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1637       element = EL_EMPTY;
1638     else
1639       element = getBorderElement(lx, ly);
1640
1641     DrawScreenElement(x, y, element);
1642     return;
1643   }
1644
1645   element = Feld[lx][ly];
1646   content = Store[lx][ly];
1647
1648   if (IS_MOVING(lx, ly))
1649   {
1650     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1651     boolean cut_mode = NO_CUTTING;
1652
1653     if (element == EL_QUICKSAND_EMPTYING ||
1654         element == EL_QUICKSAND_FAST_EMPTYING ||
1655         element == EL_MAGIC_WALL_EMPTYING ||
1656         element == EL_BD_MAGIC_WALL_EMPTYING ||
1657         element == EL_DC_MAGIC_WALL_EMPTYING ||
1658         element == EL_AMOEBA_DROPPING)
1659       cut_mode = CUT_ABOVE;
1660     else if (element == EL_QUICKSAND_FILLING ||
1661              element == EL_QUICKSAND_FAST_FILLING ||
1662              element == EL_MAGIC_WALL_FILLING ||
1663              element == EL_BD_MAGIC_WALL_FILLING ||
1664              element == EL_DC_MAGIC_WALL_FILLING)
1665       cut_mode = CUT_BELOW;
1666
1667     if (cut_mode == CUT_ABOVE)
1668       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1669     else
1670       DrawScreenElement(x, y, EL_EMPTY);
1671
1672     if (horiz_move)
1673       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1674     else if (cut_mode == NO_CUTTING)
1675       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1676     else
1677       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1678
1679     if (content == EL_ACID)
1680     {
1681       int dir = MovDir[lx][ly];
1682       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1683       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
1684
1685       DrawLevelElementThruMask(newlx, newly, EL_ACID);
1686     }
1687   }
1688   else if (IS_BLOCKED(lx, ly))
1689   {
1690     int oldx, oldy;
1691     int sx, sy;
1692     int horiz_move;
1693     boolean cut_mode = NO_CUTTING;
1694     int element_old, content_old;
1695
1696     Blocked2Moving(lx, ly, &oldx, &oldy);
1697     sx = SCREENX(oldx);
1698     sy = SCREENY(oldy);
1699     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1700                   MovDir[oldx][oldy] == MV_RIGHT);
1701
1702     element_old = Feld[oldx][oldy];
1703     content_old = Store[oldx][oldy];
1704
1705     if (element_old == EL_QUICKSAND_EMPTYING ||
1706         element_old == EL_QUICKSAND_FAST_EMPTYING ||
1707         element_old == EL_MAGIC_WALL_EMPTYING ||
1708         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1709         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1710         element_old == EL_AMOEBA_DROPPING)
1711       cut_mode = CUT_ABOVE;
1712
1713     DrawScreenElement(x, y, EL_EMPTY);
1714
1715     if (horiz_move)
1716       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1717                                NO_CUTTING);
1718     else if (cut_mode == NO_CUTTING)
1719       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1720                                cut_mode);
1721     else
1722       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1723                                cut_mode);
1724   }
1725   else if (IS_DRAWABLE(element))
1726     DrawScreenElement(x, y, element);
1727   else
1728     DrawScreenElement(x, y, EL_EMPTY);
1729 }
1730
1731 void DrawLevelField(int x, int y)
1732 {
1733   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1734     DrawScreenField(SCREENX(x), SCREENY(y));
1735   else if (IS_MOVING(x, y))
1736   {
1737     int newx,newy;
1738
1739     Moving2Blocked(x, y, &newx, &newy);
1740     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1741       DrawScreenField(SCREENX(newx), SCREENY(newy));
1742   }
1743   else if (IS_BLOCKED(x, y))
1744   {
1745     int oldx, oldy;
1746
1747     Blocked2Moving(x, y, &oldx, &oldy);
1748     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1749       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1750   }
1751 }
1752
1753 void DrawMiniElement(int x, int y, int element)
1754 {
1755   int graphic;
1756
1757   graphic = el2edimg(element);
1758   DrawMiniGraphic(x, y, graphic);
1759 }
1760
1761 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1762 {
1763   int x = sx + scroll_x, y = sy + scroll_y;
1764
1765   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1766     DrawMiniElement(sx, sy, EL_EMPTY);
1767   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1768     DrawMiniElement(sx, sy, Feld[x][y]);
1769   else
1770     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1771 }
1772
1773 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1774                             int x, int y, int xsize, int ysize, int font_nr)
1775 {
1776   int font_width  = getFontWidth(font_nr);
1777   int font_height = getFontHeight(font_nr);
1778   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1779   Bitmap *src_bitmap;
1780   int src_x, src_y;
1781   int dst_x = SX + startx + x * font_width;
1782   int dst_y = SY + starty + y * font_height;
1783   int width  = graphic_info[graphic].width;
1784   int height = graphic_info[graphic].height;
1785   int inner_width  = MAX(width  - 2 * font_width,  font_width);
1786   int inner_height = MAX(height - 2 * font_height, font_height);
1787   int inner_sx = (width >= 3 * font_width ? font_width : 0);
1788   int inner_sy = (height >= 3 * font_height ? font_height : 0);
1789   boolean draw_masked = graphic_info[graphic].draw_masked;
1790
1791   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1792
1793   if (src_bitmap == NULL || width < font_width || height < font_height)
1794   {
1795     ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1796     return;
1797   }
1798
1799   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
1800             inner_sx + (x - 1) * font_width  % inner_width);
1801   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1802             inner_sy + (y - 1) * font_height % inner_height);
1803
1804   if (draw_masked)
1805   {
1806     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1807                   dst_x - src_x, dst_y - src_y);
1808     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1809                      dst_x, dst_y);
1810   }
1811   else
1812     BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1813                dst_x, dst_y);
1814 }
1815
1816 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1817 {
1818   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1819   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1820   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1821   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1822   boolean no_delay = (tape.warp_forward);
1823   unsigned long anim_delay = 0;
1824   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1825   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1826   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1827   int font_width = getFontWidth(font_nr);
1828   int font_height = getFontHeight(font_nr);
1829   int max_xsize = level.envelope[envelope_nr].xsize;
1830   int max_ysize = level.envelope[envelope_nr].ysize;
1831   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1832   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1833   int xend = max_xsize;
1834   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1835   int xstep = (xstart < xend ? 1 : 0);
1836   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1837   int x, y;
1838
1839   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1840   {
1841     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1842     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1843     int sx = (SXSIZE - xsize * font_width)  / 2;
1844     int sy = (SYSIZE - ysize * font_height) / 2;
1845     int xx, yy;
1846
1847     SetDrawtoField(DRAW_BUFFERED);
1848
1849     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1850
1851     SetDrawtoField(DRAW_BACKBUFFER);
1852
1853     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1854       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1855
1856 #if 1
1857     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1858                    level.envelope[envelope_nr].text, font_nr, max_xsize,
1859                    xsize - 2, ysize - 2, mask_mode,
1860                    level.envelope[envelope_nr].autowrap,
1861                    level.envelope[envelope_nr].centered, FALSE);
1862 #else
1863     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1864                        level.envelope[envelope_nr].text, font_nr, max_xsize,
1865                        xsize - 2, ysize - 2, mask_mode);
1866 #endif
1867
1868     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1869     BackToFront();
1870
1871     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1872   }
1873 }
1874
1875 void ShowEnvelope(int envelope_nr)
1876 {
1877   int element = EL_ENVELOPE_1 + envelope_nr;
1878   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1879   int sound_opening = element_info[element].sound[ACTION_OPENING];
1880   int sound_closing = element_info[element].sound[ACTION_CLOSING];
1881   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1882   boolean no_delay = (tape.warp_forward);
1883   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1884   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1885   int anim_mode = graphic_info[graphic].anim_mode;
1886   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1887                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1888
1889   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
1890
1891   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1892
1893   if (anim_mode == ANIM_DEFAULT)
1894     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1895
1896   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1897
1898   if (tape.playing)
1899     Delay(wait_delay_value);
1900   else
1901     WaitForEventToContinue();
1902
1903   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1904
1905   if (anim_mode != ANIM_NONE)
1906     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1907
1908   if (anim_mode == ANIM_DEFAULT)
1909     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1910
1911   game.envelope_active = FALSE;
1912
1913   SetDrawtoField(DRAW_BUFFERED);
1914
1915   redraw_mask |= REDRAW_FIELD;
1916   BackToFront();
1917 }
1918
1919 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1920 {
1921   Bitmap *src_bitmap;
1922   int src_x, src_y;
1923   int graphic = el2preimg(element);
1924
1925   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1926   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1927 }
1928
1929 void DrawLevel()
1930 {
1931   int x,y;
1932
1933   SetDrawBackgroundMask(REDRAW_NONE);
1934   ClearWindow();
1935
1936   for (x = BX1; x <= BX2; x++)
1937     for (y = BY1; y <= BY2; y++)
1938       DrawScreenField(x, y);
1939
1940   redraw_mask |= REDRAW_FIELD;
1941 }
1942
1943 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1944 {
1945   int x,y;
1946
1947   for (x = 0; x < size_x; x++)
1948     for (y = 0; y < size_y; y++)
1949       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1950
1951   redraw_mask |= REDRAW_FIELD;
1952 }
1953
1954 static void DrawPreviewLevelExt(int from_x, int from_y)
1955 {
1956   boolean show_level_border = (BorderElement != EL_EMPTY);
1957   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1958   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1959   int tile_size = preview.tile_size;
1960   int preview_width  = preview.xsize * tile_size;
1961   int preview_height = preview.ysize * tile_size;
1962   int real_preview_xsize = MIN(level_xsize, preview.xsize);
1963   int real_preview_ysize = MIN(level_ysize, preview.ysize);
1964   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1965   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1966   int x, y;
1967
1968   DrawBackground(dst_x, dst_y, preview_width, preview_height);
1969
1970   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
1971   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
1972
1973   for (x = 0; x < real_preview_xsize; x++)
1974   {
1975     for (y = 0; y < real_preview_ysize; y++)
1976     {
1977       int lx = from_x + x + (show_level_border ? -1 : 0);
1978       int ly = from_y + y + (show_level_border ? -1 : 0);
1979       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
1980                      getBorderElement(lx, ly));
1981
1982       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
1983                          element, tile_size);
1984     }
1985   }
1986
1987   redraw_mask |= REDRAW_MICROLEVEL;
1988 }
1989
1990 #define MICROLABEL_EMPTY                0
1991 #define MICROLABEL_LEVEL_NAME           1
1992 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
1993 #define MICROLABEL_LEVEL_AUTHOR         3
1994 #define MICROLABEL_IMPORTED_FROM_HEAD   4
1995 #define MICROLABEL_IMPORTED_FROM        5
1996 #define MICROLABEL_IMPORTED_BY_HEAD     6
1997 #define MICROLABEL_IMPORTED_BY          7
1998
1999 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2000 {
2001   int max_text_width = SXSIZE;
2002   int font_width = getFontWidth(font_nr);
2003
2004   if (pos->align == ALIGN_CENTER)
2005     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2006   else if (pos->align == ALIGN_RIGHT)
2007     max_text_width = pos->x;
2008   else
2009     max_text_width = SXSIZE - pos->x;
2010
2011   return max_text_width / font_width;
2012 }
2013
2014 static void DrawPreviewLevelLabelExt(int mode)
2015 {
2016   struct TextPosInfo *pos = &menu.main.text.level_info_2;
2017   char label_text[MAX_OUTPUT_LINESIZE + 1];
2018   int max_len_label_text;
2019 #if 1
2020   int font_nr = pos->font;
2021   int i;
2022
2023   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2024       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2025       mode == MICROLABEL_IMPORTED_BY_HEAD)
2026     font_nr = pos->font_alt;
2027 #else
2028   int font_nr = FONT_TEXT_2;
2029   int i;
2030
2031   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2032       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2033       mode == MICROLABEL_IMPORTED_BY_HEAD)
2034     font_nr = FONT_TEXT_3;
2035 #endif
2036
2037 #if 1
2038   max_len_label_text = getMaxTextLength(pos, font_nr);
2039 #else
2040   max_len_label_text = SXSIZE / getFontWidth(font_nr);
2041 #endif
2042
2043 #if 1
2044   if (pos->size != -1)
2045     max_len_label_text = pos->size;
2046 #endif
2047
2048   for (i = 0; i < max_len_label_text; i++)
2049     label_text[i] = ' ';
2050   label_text[max_len_label_text] = '\0';
2051
2052   if (strlen(label_text) > 0)
2053   {
2054 #if 1
2055     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2056 #else
2057     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2058     int lypos = MICROLABEL2_YPOS;
2059
2060     DrawText(lxpos, lypos, label_text, font_nr);
2061 #endif
2062   }
2063
2064   strncpy(label_text,
2065           (mode == MICROLABEL_LEVEL_NAME ? level.name :
2066            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2067            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2068            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2069            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2070            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2071            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2072           max_len_label_text);
2073   label_text[max_len_label_text] = '\0';
2074
2075   if (strlen(label_text) > 0)
2076   {
2077 #if 1
2078     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2079 #else
2080     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2081     int lypos = MICROLABEL2_YPOS;
2082
2083     DrawText(lxpos, lypos, label_text, font_nr);
2084 #endif
2085   }
2086
2087   redraw_mask |= REDRAW_MICROLEVEL;
2088 }
2089
2090 void DrawPreviewLevel(boolean restart)
2091 {
2092   static unsigned long scroll_delay = 0;
2093   static unsigned long label_delay = 0;
2094   static int from_x, from_y, scroll_direction;
2095   static int label_state, label_counter;
2096   unsigned long scroll_delay_value = preview.step_delay;
2097   boolean show_level_border = (BorderElement != EL_EMPTY);
2098   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2099   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2100   int last_game_status = game_status;           /* save current game status */
2101
2102 #if 0
2103   /* force PREVIEW font on preview level */
2104   game_status = GAME_MODE_PSEUDO_PREVIEW;
2105 #endif
2106
2107   if (restart)
2108   {
2109     from_x = 0;
2110     from_y = 0;
2111
2112     if (preview.anim_mode == ANIM_CENTERED)
2113     {
2114       if (level_xsize > preview.xsize)
2115         from_x = (level_xsize - preview.xsize) / 2;
2116       if (level_ysize > preview.ysize)
2117         from_y = (level_ysize - preview.ysize) / 2;
2118     }
2119
2120     from_x += preview.xoffset;
2121     from_y += preview.yoffset;
2122
2123     scroll_direction = MV_RIGHT;
2124     label_state = 1;
2125     label_counter = 0;
2126
2127     DrawPreviewLevelExt(from_x, from_y);
2128     DrawPreviewLevelLabelExt(label_state);
2129
2130     /* initialize delay counters */
2131     DelayReached(&scroll_delay, 0);
2132     DelayReached(&label_delay, 0);
2133
2134     if (leveldir_current->name)
2135     {
2136       struct TextPosInfo *pos = &menu.main.text.level_info_1;
2137       char label_text[MAX_OUTPUT_LINESIZE + 1];
2138 #if 1
2139       int font_nr = pos->font;
2140 #else
2141       int font_nr = FONT_TEXT_1;
2142 #endif
2143 #if 1
2144       int max_len_label_text = getMaxTextLength(pos, font_nr);
2145 #else
2146       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2147 #endif
2148 #if 0
2149       int text_width;
2150       int lxpos, lypos;
2151 #endif
2152
2153 #if 1
2154       if (pos->size != -1)
2155         max_len_label_text = pos->size;
2156 #endif
2157
2158       strncpy(label_text, leveldir_current->name, max_len_label_text);
2159       label_text[max_len_label_text] = '\0';
2160
2161 #if 1
2162       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2163 #else
2164       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2165       lypos = SY + MICROLABEL1_YPOS;
2166
2167       DrawText(lxpos, lypos, label_text, font_nr);
2168 #endif
2169     }
2170
2171     game_status = last_game_status;     /* restore current game status */
2172
2173     return;
2174   }
2175
2176   /* scroll preview level, if needed */
2177   if (preview.anim_mode != ANIM_NONE &&
2178       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2179       DelayReached(&scroll_delay, scroll_delay_value))
2180   {
2181     switch (scroll_direction)
2182     {
2183       case MV_LEFT:
2184         if (from_x > 0)
2185         {
2186           from_x -= preview.step_offset;
2187           from_x = (from_x < 0 ? 0 : from_x);
2188         }
2189         else
2190           scroll_direction = MV_UP;
2191         break;
2192
2193       case MV_RIGHT:
2194         if (from_x < level_xsize - preview.xsize)
2195         {
2196           from_x += preview.step_offset;
2197           from_x = (from_x > level_xsize - preview.xsize ?
2198                     level_xsize - preview.xsize : from_x);
2199         }
2200         else
2201           scroll_direction = MV_DOWN;
2202         break;
2203
2204       case MV_UP:
2205         if (from_y > 0)
2206         {
2207           from_y -= preview.step_offset;
2208           from_y = (from_y < 0 ? 0 : from_y);
2209         }
2210         else
2211           scroll_direction = MV_RIGHT;
2212         break;
2213
2214       case MV_DOWN:
2215         if (from_y < level_ysize - preview.ysize)
2216         {
2217           from_y += preview.step_offset;
2218           from_y = (from_y > level_ysize - preview.ysize ?
2219                     level_ysize - preview.ysize : from_y);
2220         }
2221         else
2222           scroll_direction = MV_LEFT;
2223         break;
2224
2225       default:
2226         break;
2227     }
2228
2229     DrawPreviewLevelExt(from_x, from_y);
2230   }
2231
2232   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2233   /* redraw micro level label, if needed */
2234   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2235       !strEqual(level.author, ANONYMOUS_NAME) &&
2236       !strEqual(level.author, leveldir_current->name) &&
2237       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2238   {
2239     int max_label_counter = 23;
2240
2241     if (leveldir_current->imported_from != NULL &&
2242         strlen(leveldir_current->imported_from) > 0)
2243       max_label_counter += 14;
2244     if (leveldir_current->imported_by != NULL &&
2245         strlen(leveldir_current->imported_by) > 0)
2246       max_label_counter += 14;
2247
2248     label_counter = (label_counter + 1) % max_label_counter;
2249     label_state = (label_counter >= 0 && label_counter <= 7 ?
2250                    MICROLABEL_LEVEL_NAME :
2251                    label_counter >= 9 && label_counter <= 12 ?
2252                    MICROLABEL_LEVEL_AUTHOR_HEAD :
2253                    label_counter >= 14 && label_counter <= 21 ?
2254                    MICROLABEL_LEVEL_AUTHOR :
2255                    label_counter >= 23 && label_counter <= 26 ?
2256                    MICROLABEL_IMPORTED_FROM_HEAD :
2257                    label_counter >= 28 && label_counter <= 35 ?
2258                    MICROLABEL_IMPORTED_FROM :
2259                    label_counter >= 37 && label_counter <= 40 ?
2260                    MICROLABEL_IMPORTED_BY_HEAD :
2261                    label_counter >= 42 && label_counter <= 49 ?
2262                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2263
2264     if (leveldir_current->imported_from == NULL &&
2265         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2266          label_state == MICROLABEL_IMPORTED_FROM))
2267       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2268                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2269
2270     DrawPreviewLevelLabelExt(label_state);
2271   }
2272
2273   game_status = last_game_status;       /* restore current game status */
2274 }
2275
2276 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2277                                     int graphic, int sync_frame, int mask_mode)
2278 {
2279   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2280
2281   if (mask_mode == USE_MASKING)
2282     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2283   else
2284     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2285 }
2286
2287 inline void DrawGraphicAnimation(int x, int y, int graphic)
2288 {
2289   int lx = LEVELX(x), ly = LEVELY(y);
2290
2291   if (!IN_SCR_FIELD(x, y))
2292     return;
2293
2294   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2295                           graphic, GfxFrame[lx][ly], NO_MASKING);
2296   MarkTileDirty(x, y);
2297 }
2298
2299 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2300 {
2301   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2302 }
2303
2304 void DrawLevelElementAnimation(int x, int y, int element)
2305 {
2306   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2307
2308   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2309 }
2310
2311 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2312 {
2313   int sx = SCREENX(x), sy = SCREENY(y);
2314
2315   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2316     return;
2317
2318   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2319     return;
2320
2321   DrawGraphicAnimation(sx, sy, graphic);
2322
2323 #if 1
2324   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2325     DrawLevelFieldCrumbledSand(x, y);
2326 #else
2327   if (GFX_CRUMBLED(Feld[x][y]))
2328     DrawLevelFieldCrumbledSand(x, y);
2329 #endif
2330 }
2331
2332 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2333 {
2334   int sx = SCREENX(x), sy = SCREENY(y);
2335   int graphic;
2336
2337   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2338     return;
2339
2340   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2341
2342   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2343     return;
2344
2345   DrawGraphicAnimation(sx, sy, graphic);
2346
2347   if (GFX_CRUMBLED(element))
2348     DrawLevelFieldCrumbledSand(x, y);
2349 }
2350
2351 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2352 {
2353   if (player->use_murphy)
2354   {
2355     /* this works only because currently only one player can be "murphy" ... */
2356     static int last_horizontal_dir = MV_LEFT;
2357     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2358
2359     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2360       last_horizontal_dir = move_dir;
2361
2362     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
2363     {
2364       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2365
2366       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2367     }
2368
2369     return graphic;
2370   }
2371   else
2372     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2373 }
2374
2375 static boolean equalGraphics(int graphic1, int graphic2)
2376 {
2377   struct GraphicInfo *g1 = &graphic_info[graphic1];
2378   struct GraphicInfo *g2 = &graphic_info[graphic2];
2379
2380   return (g1->bitmap      == g2->bitmap &&
2381           g1->src_x       == g2->src_x &&
2382           g1->src_y       == g2->src_y &&
2383           g1->anim_frames == g2->anim_frames &&
2384           g1->anim_delay  == g2->anim_delay &&
2385           g1->anim_mode   == g2->anim_mode);
2386 }
2387
2388 void DrawAllPlayers()
2389 {
2390   int i;
2391
2392   for (i = 0; i < MAX_PLAYERS; i++)
2393     if (stored_player[i].active)
2394       DrawPlayer(&stored_player[i]);
2395 }
2396
2397 void DrawPlayerField(int x, int y)
2398 {
2399   if (!IS_PLAYER(x, y))
2400     return;
2401
2402   DrawPlayer(PLAYERINFO(x, y));
2403 }
2404
2405 void DrawPlayer(struct PlayerInfo *player)
2406 {
2407   int jx = player->jx;
2408   int jy = player->jy;
2409   int move_dir = player->MovDir;
2410   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2411   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
2412   int last_jx = (player->is_moving ? jx - dx : jx);
2413   int last_jy = (player->is_moving ? jy - dy : jy);
2414   int next_jx = jx + dx;
2415   int next_jy = jy + dy;
2416   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2417   boolean player_is_opaque = FALSE;
2418   int sx = SCREENX(jx), sy = SCREENY(jy);
2419   int sxx = 0, syy = 0;
2420   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2421   int graphic;
2422   int action = ACTION_DEFAULT;
2423   int last_player_graphic = getPlayerGraphic(player, move_dir);
2424   int last_player_frame = player->Frame;
2425   int frame = 0;
2426
2427   /* GfxElement[][] is set to the element the player is digging or collecting;
2428      remove also for off-screen player if the player is not moving anymore */
2429   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2430     GfxElement[jx][jy] = EL_UNDEFINED;
2431
2432   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2433     return;
2434
2435 #if DEBUG
2436   if (!IN_LEV_FIELD(jx, jy))
2437   {
2438     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2439     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2440     printf("DrawPlayerField(): This should never happen!\n");
2441     return;
2442   }
2443 #endif
2444
2445   if (element == EL_EXPLOSION)
2446     return;
2447
2448   action = (player->is_pushing    ? ACTION_PUSHING         :
2449             player->is_digging    ? ACTION_DIGGING         :
2450             player->is_collecting ? ACTION_COLLECTING      :
2451             player->is_moving     ? ACTION_MOVING          :
2452             player->is_snapping   ? ACTION_SNAPPING        :
2453             player->is_dropping   ? ACTION_DROPPING        :
2454             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
2455
2456   if (player->is_waiting)
2457     move_dir = player->dir_waiting;
2458
2459   InitPlayerGfxAnimation(player, action, move_dir);
2460
2461   /* ----------------------------------------------------------------------- */
2462   /* draw things in the field the player is leaving, if needed               */
2463   /* ----------------------------------------------------------------------- */
2464
2465   if (player->is_moving)
2466   {
2467     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2468     {
2469       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2470
2471       if (last_element == EL_DYNAMITE_ACTIVE ||
2472           last_element == EL_EM_DYNAMITE_ACTIVE ||
2473           last_element == EL_SP_DISK_RED_ACTIVE)
2474         DrawDynamite(last_jx, last_jy);
2475       else
2476         DrawLevelFieldThruMask(last_jx, last_jy);
2477     }
2478     else if (last_element == EL_DYNAMITE_ACTIVE ||
2479              last_element == EL_EM_DYNAMITE_ACTIVE ||
2480              last_element == EL_SP_DISK_RED_ACTIVE)
2481       DrawDynamite(last_jx, last_jy);
2482 #if 0
2483     /* !!! this is not enough to prevent flickering of players which are
2484        moving next to each others without a free tile between them -- this
2485        can only be solved by drawing all players layer by layer (first the
2486        background, then the foreground etc.) !!! => TODO */
2487     else if (!IS_PLAYER(last_jx, last_jy))
2488       DrawLevelField(last_jx, last_jy);
2489 #else
2490     else
2491       DrawLevelField(last_jx, last_jy);
2492 #endif
2493
2494     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2495       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2496   }
2497
2498   if (!IN_SCR_FIELD(sx, sy))
2499     return;
2500
2501   if (setup.direct_draw)
2502     SetDrawtoField(DRAW_BUFFERED);
2503
2504   /* ----------------------------------------------------------------------- */
2505   /* draw things behind the player, if needed                                */
2506   /* ----------------------------------------------------------------------- */
2507
2508   if (Back[jx][jy])
2509     DrawLevelElement(jx, jy, Back[jx][jy]);
2510   else if (IS_ACTIVE_BOMB(element))
2511     DrawLevelElement(jx, jy, EL_EMPTY);
2512   else
2513   {
2514     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2515     {
2516       int old_element = GfxElement[jx][jy];
2517       int old_graphic = el_act_dir2img(old_element, action, move_dir);
2518       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2519
2520       if (GFX_CRUMBLED(old_element))
2521         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2522       else
2523         DrawGraphic(sx, sy, old_graphic, frame);
2524
2525       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2526         player_is_opaque = TRUE;
2527     }
2528     else
2529     {
2530       GfxElement[jx][jy] = EL_UNDEFINED;
2531
2532       /* make sure that pushed elements are drawn with correct frame rate */
2533 #if 1
2534       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2535
2536       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2537         GfxFrame[jx][jy] = player->StepFrame;
2538 #else
2539       if (player->is_pushing && player->is_moving)
2540         GfxFrame[jx][jy] = player->StepFrame;
2541 #endif
2542
2543       DrawLevelField(jx, jy);
2544     }
2545   }
2546
2547   /* ----------------------------------------------------------------------- */
2548   /* draw player himself                                                     */
2549   /* ----------------------------------------------------------------------- */
2550
2551   graphic = getPlayerGraphic(player, move_dir);
2552
2553   /* in the case of changed player action or direction, prevent the current
2554      animation frame from being restarted for identical animations */
2555   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2556     player->Frame = last_player_frame;
2557
2558   frame = getGraphicAnimationFrame(graphic, player->Frame);
2559
2560   if (player->GfxPos)
2561   {
2562     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2563       sxx = player->GfxPos;
2564     else
2565       syy = player->GfxPos;
2566   }
2567
2568   if (!setup.soft_scrolling && ScreenMovPos)
2569     sxx = syy = 0;
2570
2571   if (player_is_opaque)
2572     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2573   else
2574     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2575
2576   if (SHIELD_ON(player))
2577   {
2578     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2579                    IMG_SHIELD_NORMAL_ACTIVE);
2580     int frame = getGraphicAnimationFrame(graphic, -1);
2581
2582     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2583   }
2584
2585   /* ----------------------------------------------------------------------- */
2586   /* draw things the player is pushing, if needed                            */
2587   /* ----------------------------------------------------------------------- */
2588
2589 #if 0
2590   printf("::: %d, %d [%d, %d] [%d]\n",
2591          player->is_pushing, player_is_moving, player->GfxAction,
2592          player->is_moving, player_is_moving);
2593 #endif
2594
2595 #if 1
2596   if (player->is_pushing && player->is_moving)
2597   {
2598     int px = SCREENX(jx), py = SCREENY(jy);
2599     int pxx = (TILEX - ABS(sxx)) * dx;
2600     int pyy = (TILEY - ABS(syy)) * dy;
2601     int gfx_frame = GfxFrame[jx][jy];
2602
2603     int graphic;
2604     int sync_frame;
2605     int frame;
2606
2607     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2608     {
2609       element = Feld[next_jx][next_jy];
2610       gfx_frame = GfxFrame[next_jx][next_jy];
2611     }
2612
2613     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2614
2615 #if 1
2616     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2617     frame = getGraphicAnimationFrame(graphic, sync_frame);
2618 #else
2619     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2620 #endif
2621
2622     /* draw background element under pushed element (like the Sokoban field) */
2623     if (Back[next_jx][next_jy])
2624       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2625
2626     /* masked drawing is needed for EMC style (double) movement graphics */
2627     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2628   }
2629 #endif
2630
2631   /* ----------------------------------------------------------------------- */
2632   /* draw things in front of player (active dynamite or dynabombs)           */
2633   /* ----------------------------------------------------------------------- */
2634
2635   if (IS_ACTIVE_BOMB(element))
2636   {
2637     graphic = el2img(element);
2638     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2639
2640     if (game.emulation == EMU_SUPAPLEX)
2641       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2642     else
2643       DrawGraphicThruMask(sx, sy, graphic, frame);
2644   }
2645
2646   if (player_is_moving && last_element == EL_EXPLOSION)
2647   {
2648     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2649                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2650     int graphic = el_act2img(element, ACTION_EXPLODING);
2651     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2652     int phase = ExplodePhase[last_jx][last_jy] - 1;
2653     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2654
2655     if (phase >= delay)
2656       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2657   }
2658
2659   /* ----------------------------------------------------------------------- */
2660   /* draw elements the player is just walking/passing through/under          */
2661   /* ----------------------------------------------------------------------- */
2662
2663   if (player_is_moving)
2664   {
2665     /* handle the field the player is leaving ... */
2666     if (IS_ACCESSIBLE_INSIDE(last_element))
2667       DrawLevelField(last_jx, last_jy);
2668     else if (IS_ACCESSIBLE_UNDER(last_element))
2669       DrawLevelFieldThruMask(last_jx, last_jy);
2670   }
2671
2672   /* do not redraw accessible elements if the player is just pushing them */
2673   if (!player_is_moving || !player->is_pushing)
2674   {
2675     /* ... and the field the player is entering */
2676     if (IS_ACCESSIBLE_INSIDE(element))
2677       DrawLevelField(jx, jy);
2678     else if (IS_ACCESSIBLE_UNDER(element))
2679       DrawLevelFieldThruMask(jx, jy);
2680   }
2681
2682   if (setup.direct_draw)
2683   {
2684     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2685     int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2686     int x_size = TILEX * (1 + ABS(jx - last_jx));
2687     int y_size = TILEY * (1 + ABS(jy - last_jy));
2688
2689     BlitBitmap(drawto_field, window,
2690                dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2691     SetDrawtoField(DRAW_DIRECT);
2692   }
2693
2694   MarkTileDirty(sx, sy);
2695 }
2696
2697 /* ------------------------------------------------------------------------- */
2698
2699 void WaitForEventToContinue()
2700 {
2701   boolean still_wait = TRUE;
2702
2703   /* simulate releasing mouse button over last gadget, if still pressed */
2704   if (button_status)
2705     HandleGadgets(-1, -1, 0);
2706
2707   button_status = MB_RELEASED;
2708
2709 #if 1
2710   ClearEventQueue();
2711 #endif
2712
2713   while (still_wait)
2714   {
2715     if (PendingEvent())
2716     {
2717       Event event;
2718
2719       NextEvent(&event);
2720
2721       switch (event.type)
2722       {
2723         case EVENT_BUTTONPRESS:
2724         case EVENT_KEYPRESS:
2725           still_wait = FALSE;
2726           break;
2727
2728         case EVENT_KEYRELEASE:
2729           ClearPlayerAction();
2730           break;
2731
2732         default:
2733           HandleOtherEvents(&event);
2734           break;
2735       }
2736     }
2737     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2738     {
2739       still_wait = FALSE;
2740     }
2741
2742     DoAnimation();
2743
2744     /* don't eat all CPU time */
2745     Delay(10);
2746   }
2747 }
2748
2749 #define MAX_REQUEST_LINES               13
2750 #define MAX_REQUEST_LINE_FONT1_LEN      7
2751 #define MAX_REQUEST_LINE_FONT2_LEN      10
2752
2753 boolean Request(char *text, unsigned int req_state)
2754 {
2755   int mx, my, ty, result = -1;
2756   unsigned int old_door_state;
2757   int last_game_status = game_status;   /* save current game status */
2758   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2759   int font_nr = FONT_TEXT_2;
2760   int max_word_len = 0;
2761   char *text_ptr;
2762
2763   for (text_ptr = text; *text_ptr; text_ptr++)
2764   {
2765     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2766
2767     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2768     {
2769       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2770 #if 1
2771       font_nr = FONT_TEXT_1;
2772 #else
2773       font_nr = FONT_LEVEL_NUMBER;
2774 #endif
2775
2776       break;
2777     }
2778   }
2779
2780   if (game_status == GAME_MODE_PLAYING &&
2781       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2782     BlitScreenToBitmap_EM(backbuffer);
2783
2784   /* disable deactivated drawing when quick-loading level tape recording */
2785   if (tape.playing && tape.deactivate_display)
2786     TapeDeactivateDisplayOff(TRUE);
2787
2788   SetMouseCursor(CURSOR_DEFAULT);
2789
2790 #if defined(NETWORK_AVALIABLE)
2791   /* pause network game while waiting for request to answer */
2792   if (options.network &&
2793       game_status == GAME_MODE_PLAYING &&
2794       req_state & REQUEST_WAIT_FOR_INPUT)
2795     SendToServer_PausePlaying();
2796 #endif
2797
2798   old_door_state = GetDoorState();
2799
2800   /* simulate releasing mouse button over last gadget, if still pressed */
2801   if (button_status)
2802     HandleGadgets(-1, -1, 0);
2803
2804   UnmapAllGadgets();
2805
2806   if (old_door_state & DOOR_OPEN_1)
2807   {
2808     CloseDoor(DOOR_CLOSE_1);
2809
2810     /* save old door content */
2811     BlitBitmap(bitmap_db_door, bitmap_db_door,
2812                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2813                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2814   }
2815
2816 #if 1
2817   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2818 #endif
2819
2820   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2821
2822   /* clear door drawing field */
2823   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2824
2825   /* force DOOR font inside door area */
2826   game_status = GAME_MODE_PSEUDO_DOOR;
2827
2828   /* write text for request */
2829   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2830   {
2831     char text_line[max_request_line_len + 1];
2832     int tx, tl, tc = 0;
2833
2834     if (!*text)
2835       break;
2836
2837     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2838     {
2839       tc = *(text + tx);
2840       if (!tc || tc == ' ')
2841         break;
2842     }
2843
2844     if (!tl)
2845     { 
2846       text++; 
2847       ty--; 
2848       continue; 
2849     }
2850
2851     strncpy(text_line, text, tl);
2852     text_line[tl] = 0;
2853
2854     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2855              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2856              text_line, font_nr);
2857
2858     text += tl + (tc == ' ' ? 1 : 0);
2859   }
2860
2861   game_status = last_game_status;       /* restore current game status */
2862
2863   if (req_state & REQ_ASK)
2864   {
2865     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2866     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2867   }
2868   else if (req_state & REQ_CONFIRM)
2869   {
2870     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2871   }
2872   else if (req_state & REQ_PLAYER)
2873   {
2874     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2875     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2876     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2877     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2878   }
2879
2880   /* copy request gadgets to door backbuffer */
2881   BlitBitmap(drawto, bitmap_db_door,
2882              DX, DY, DXSIZE, DYSIZE,
2883              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2884
2885   OpenDoor(DOOR_OPEN_1);
2886
2887   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2888   {
2889     if (game_status == GAME_MODE_PLAYING)
2890     {
2891       SetPanelBackground();
2892       SetDrawBackgroundMask(REDRAW_DOOR_1);
2893     }
2894     else
2895     {
2896       SetDrawBackgroundMask(REDRAW_FIELD);
2897     }
2898
2899     return FALSE;
2900   }
2901
2902   if (game_status != GAME_MODE_MAIN)
2903     InitAnimation();
2904
2905   button_status = MB_RELEASED;
2906
2907   request_gadget_id = -1;
2908
2909   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2910
2911   while (result < 0)
2912   {
2913     if (PendingEvent())
2914     {
2915       Event event;
2916
2917       NextEvent(&event);
2918
2919       switch (event.type)
2920       {
2921         case EVENT_BUTTONPRESS:
2922         case EVENT_BUTTONRELEASE:
2923         case EVENT_MOTIONNOTIFY:
2924         {
2925           if (event.type == EVENT_MOTIONNOTIFY)
2926           {
2927             if (!PointerInWindow(window))
2928               continue; /* window and pointer are on different screens */
2929
2930             if (!button_status)
2931               continue;
2932
2933             motion_status = TRUE;
2934             mx = ((MotionEvent *) &event)->x;
2935             my = ((MotionEvent *) &event)->y;
2936           }
2937           else
2938           {
2939             motion_status = FALSE;
2940             mx = ((ButtonEvent *) &event)->x;
2941             my = ((ButtonEvent *) &event)->y;
2942             if (event.type == EVENT_BUTTONPRESS)
2943               button_status = ((ButtonEvent *) &event)->button;
2944             else
2945               button_status = MB_RELEASED;
2946           }
2947
2948           /* this sets 'request_gadget_id' */
2949           HandleGadgets(mx, my, button_status);
2950
2951           switch (request_gadget_id)
2952           {
2953             case TOOL_CTRL_ID_YES:
2954               result = TRUE;
2955               break;
2956             case TOOL_CTRL_ID_NO:
2957               result = FALSE;
2958               break;
2959             case TOOL_CTRL_ID_CONFIRM:
2960               result = TRUE | FALSE;
2961               break;
2962
2963             case TOOL_CTRL_ID_PLAYER_1:
2964               result = 1;
2965               break;
2966             case TOOL_CTRL_ID_PLAYER_2:
2967               result = 2;
2968               break;
2969             case TOOL_CTRL_ID_PLAYER_3:
2970               result = 3;
2971               break;
2972             case TOOL_CTRL_ID_PLAYER_4:
2973               result = 4;
2974               break;
2975
2976             default:
2977               break;
2978           }
2979
2980           break;
2981         }
2982
2983         case EVENT_KEYPRESS:
2984           switch (GetEventKey((KeyEvent *)&event, TRUE))
2985           {
2986             case KSYM_space:
2987               if (req_state & REQ_CONFIRM)
2988                 result = 1;
2989               break;
2990
2991             case KSYM_Return:
2992               result = 1;
2993               break;
2994
2995             case KSYM_Escape:
2996               result = 0;
2997               break;
2998
2999             default:
3000               break;
3001           }
3002
3003           if (req_state & REQ_PLAYER)
3004             result = 0;
3005           break;
3006
3007         case EVENT_KEYRELEASE:
3008           ClearPlayerAction();
3009           break;
3010
3011         default:
3012           HandleOtherEvents(&event);
3013           break;
3014       }
3015     }
3016     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3017     {
3018       int joy = AnyJoystick();
3019
3020       if (joy & JOY_BUTTON_1)
3021         result = 1;
3022       else if (joy & JOY_BUTTON_2)
3023         result = 0;
3024     }
3025
3026 #if 1
3027
3028     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3029     {
3030       HandleGameActions();
3031       BackToFront();
3032     }
3033     else
3034     {
3035       DoAnimation();
3036
3037       if (!PendingEvent())      /* delay only if no pending events */
3038         Delay(10);
3039     }
3040
3041 #else
3042
3043     DoAnimation();
3044
3045 #if 1
3046     if (!PendingEvent())        /* delay only if no pending events */
3047       Delay(10);
3048 #else
3049     /* don't eat all CPU time */
3050     Delay(10);
3051 #endif
3052
3053 #endif
3054   }
3055
3056   if (game_status != GAME_MODE_MAIN)
3057     StopAnimation();
3058
3059   UnmapToolButtons();
3060
3061   if (!(req_state & REQ_STAY_OPEN))
3062   {
3063     CloseDoor(DOOR_CLOSE_1);
3064
3065     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3066         (req_state & REQ_REOPEN))
3067       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3068   }
3069
3070   RemapAllGadgets();
3071
3072   if (game_status == GAME_MODE_PLAYING)
3073   {
3074     SetPanelBackground();
3075     SetDrawBackgroundMask(REDRAW_DOOR_1);
3076   }
3077   else
3078   {
3079     SetDrawBackgroundMask(REDRAW_FIELD);
3080   }
3081
3082 #if defined(NETWORK_AVALIABLE)
3083   /* continue network game after request */
3084   if (options.network &&
3085       game_status == GAME_MODE_PLAYING &&
3086       req_state & REQUEST_WAIT_FOR_INPUT)
3087     SendToServer_ContinuePlaying();
3088 #endif
3089
3090   /* restore deactivated drawing when quick-loading level tape recording */
3091   if (tape.playing && tape.deactivate_display)
3092     TapeDeactivateDisplayOn();
3093
3094   return result;
3095 }
3096
3097 unsigned int OpenDoor(unsigned int door_state)
3098 {
3099   if (door_state & DOOR_COPY_BACK)
3100   {
3101     if (door_state & DOOR_OPEN_1)
3102       BlitBitmap(bitmap_db_door, bitmap_db_door,
3103                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3104                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3105
3106     if (door_state & DOOR_OPEN_2)
3107       BlitBitmap(bitmap_db_door, bitmap_db_door,
3108                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3109                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3110
3111     door_state &= ~DOOR_COPY_BACK;
3112   }
3113
3114   return MoveDoor(door_state);
3115 }
3116
3117 unsigned int CloseDoor(unsigned int door_state)
3118 {
3119   unsigned int old_door_state = GetDoorState();
3120
3121   if (!(door_state & DOOR_NO_COPY_BACK))
3122   {
3123     if (old_door_state & DOOR_OPEN_1)
3124       BlitBitmap(backbuffer, bitmap_db_door,
3125                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3126
3127     if (old_door_state & DOOR_OPEN_2)
3128       BlitBitmap(backbuffer, bitmap_db_door,
3129                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3130
3131     door_state &= ~DOOR_NO_COPY_BACK;
3132   }
3133
3134   return MoveDoor(door_state);
3135 }
3136
3137 unsigned int GetDoorState()
3138 {
3139   return MoveDoor(DOOR_GET_STATE);
3140 }
3141
3142 unsigned int SetDoorState(unsigned int door_state)
3143 {
3144   return MoveDoor(door_state | DOOR_SET_STATE);
3145 }
3146
3147 unsigned int MoveDoor(unsigned int door_state)
3148 {
3149   static int door1 = DOOR_OPEN_1;
3150   static int door2 = DOOR_CLOSE_2;
3151   unsigned long door_delay = 0;
3152   unsigned long door_delay_value;
3153   int stepsize = 1;
3154
3155   if (door_1.width < 0 || door_1.width > DXSIZE)
3156     door_1.width = DXSIZE;
3157   if (door_1.height < 0 || door_1.height > DYSIZE)
3158     door_1.height = DYSIZE;
3159   if (door_2.width < 0 || door_2.width > VXSIZE)
3160     door_2.width = VXSIZE;
3161   if (door_2.height < 0 || door_2.height > VYSIZE)
3162     door_2.height = VYSIZE;
3163
3164   if (door_state == DOOR_GET_STATE)
3165     return (door1 | door2);
3166
3167   if (door_state & DOOR_SET_STATE)
3168   {
3169     if (door_state & DOOR_ACTION_1)
3170       door1 = door_state & DOOR_ACTION_1;
3171     if (door_state & DOOR_ACTION_2)
3172       door2 = door_state & DOOR_ACTION_2;
3173
3174     return (door1 | door2);
3175   }
3176
3177   if (!(door_state & DOOR_FORCE_REDRAW))
3178   {
3179     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3180       door_state &= ~DOOR_OPEN_1;
3181     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3182       door_state &= ~DOOR_CLOSE_1;
3183     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3184       door_state &= ~DOOR_OPEN_2;
3185     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3186       door_state &= ~DOOR_CLOSE_2;
3187   }
3188
3189   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3190                       door_2.step_delay);
3191
3192   if (setup.quick_doors)
3193   {
3194     stepsize = 20;              /* must be chosen to always draw last frame */
3195     door_delay_value = 0;
3196   }
3197
3198   if (global.autoplay_leveldir)
3199   {
3200     door_state |= DOOR_NO_DELAY;
3201     door_state &= ~DOOR_CLOSE_ALL;
3202   }
3203
3204   if (door_state & DOOR_ACTION)
3205   {
3206     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3207     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3208     boolean door_1_done = (!handle_door_1);
3209     boolean door_2_done = (!handle_door_2);
3210     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3211     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3212     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3213     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3214     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3215     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3216     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
3217     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3218     int door_skip = max_door_size - door_size;
3219     int end = door_size;
3220     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3221     int k;
3222
3223     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3224     {
3225       /* opening door sound has priority over simultaneously closing door */
3226       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3227         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3228       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3229         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3230     }
3231
3232     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3233     {
3234       int x = k;
3235       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3236       GC gc = bitmap->stored_clip_gc;
3237
3238       if (door_state & DOOR_ACTION_1)
3239       {
3240         int a = MIN(x * door_1.step_offset, end);
3241         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3242         int i = p + door_skip;
3243
3244         if (door_1.anim_mode & ANIM_STATIC_PANEL)
3245         {
3246           BlitBitmap(bitmap_db_door, drawto,
3247                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3248                      DXSIZE, DYSIZE, DX, DY);
3249         }
3250         else if (x <= a)
3251         {
3252           BlitBitmap(bitmap_db_door, drawto,
3253                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3254                      DXSIZE, DYSIZE - p / 2, DX, DY);
3255
3256           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3257         }
3258
3259         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3260         {
3261           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3262           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3263           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
3264           int dst2_x = DX,              dst2_y = DY;
3265           int width = i, height = DYSIZE;
3266
3267           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3268           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3269                            dst1_x, dst1_y);
3270
3271           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3272           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3273                            dst2_x, dst2_y);
3274         }
3275         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3276         {
3277           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3278           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
3279           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3280           int dst2_x = DX,              dst2_y = DY;
3281           int width = DXSIZE, height = i;
3282
3283           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3284           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3285                            dst1_x, dst1_y);
3286
3287           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3288           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3289                            dst2_x, dst2_y);
3290         }
3291         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
3292         {
3293           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3294
3295           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3296           BlitBitmapMasked(bitmap, drawto,
3297                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3298                            DX + DXSIZE - i, DY + j);
3299           BlitBitmapMasked(bitmap, drawto,
3300                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3301                            DX + DXSIZE - i, DY + 140 + j);
3302           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3303                         DY - (DOOR_GFX_PAGEY1 + j));
3304           BlitBitmapMasked(bitmap, drawto,
3305                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3306                            DX, DY);
3307           BlitBitmapMasked(bitmap, drawto,
3308                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3309                            DX, DY + 140 - j);
3310
3311           BlitBitmapMasked(bitmap, drawto,
3312                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3313                            DX, DY + 77 - j);
3314           BlitBitmapMasked(bitmap, drawto,
3315                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3316                            DX, DY + 203 - j);
3317           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3318           BlitBitmapMasked(bitmap, drawto,
3319                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3320                            DX + DXSIZE - i, DY + 77 + j);
3321           BlitBitmapMasked(bitmap, drawto,
3322                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3323                            DX + DXSIZE - i, DY + 203 + j);
3324         }
3325
3326         redraw_mask |= REDRAW_DOOR_1;
3327         door_1_done = (a == end);
3328       }
3329
3330       if (door_state & DOOR_ACTION_2)
3331       {
3332         int a = MIN(x * door_2.step_offset, door_size);
3333         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3334         int i = p + door_skip;
3335
3336         if (door_2.anim_mode & ANIM_STATIC_PANEL)
3337         {
3338           BlitBitmap(bitmap_db_door, drawto,
3339                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3340                      VXSIZE, VYSIZE, VX, VY);
3341         }
3342         else if (x <= VYSIZE)
3343         {
3344           BlitBitmap(bitmap_db_door, drawto,
3345                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3346                      VXSIZE, VYSIZE - p / 2, VX, VY);
3347
3348           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3349         }
3350
3351         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3352         {
3353           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3354           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3355           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
3356           int dst2_x = VX,              dst2_y = VY;
3357           int width = i, height = VYSIZE;
3358
3359           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3360           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3361                            dst1_x, dst1_y);
3362
3363           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3364           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3365                            dst2_x, dst2_y);
3366         }
3367         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3368         {
3369           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3370           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
3371           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3372           int dst2_x = VX,              dst2_y = VY;
3373           int width = VXSIZE, height = i;
3374
3375           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3376           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3377                            dst1_x, dst1_y);
3378
3379           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3380           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3381                            dst2_x, dst2_y);
3382         }
3383         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
3384         {
3385           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3386
3387           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3388           BlitBitmapMasked(bitmap, drawto,
3389                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3390                            VX + VXSIZE - i, VY + j);
3391           SetClipOrigin(bitmap, gc,
3392                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3393           BlitBitmapMasked(bitmap, drawto,
3394                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3395                            VX, VY);
3396
3397           BlitBitmapMasked(bitmap, drawto,
3398                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3399                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3400           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3401           BlitBitmapMasked(bitmap, drawto,
3402                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3403                            i, VYSIZE / 2 - j,
3404                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3405         }
3406
3407         redraw_mask |= REDRAW_DOOR_2;
3408         door_2_done = (a == VXSIZE);
3409       }
3410
3411       if (!(door_state & DOOR_NO_DELAY))
3412       {
3413         BackToFront();
3414
3415         if (game_status == GAME_MODE_MAIN)
3416           DoAnimation();
3417
3418         WaitUntilDelayReached(&door_delay, door_delay_value);
3419       }
3420     }
3421   }
3422
3423   if (door_state & DOOR_ACTION_1)
3424     door1 = door_state & DOOR_ACTION_1;
3425   if (door_state & DOOR_ACTION_2)
3426     door2 = door_state & DOOR_ACTION_2;
3427
3428   return (door1 | door2);
3429 }
3430
3431 void DrawSpecialEditorDoor()
3432 {
3433   /* draw bigger toolbox window */
3434   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3435              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3436              EX - 4, EY - 12);
3437   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3438              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3439              EX - 6, EY - 4);
3440
3441   redraw_mask |= REDRAW_ALL;
3442 }
3443
3444 void UndrawSpecialEditorDoor()
3445 {
3446   /* draw normal tape recorder window */
3447   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3448              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3449              EX - 6, EY - 12);
3450
3451   redraw_mask |= REDRAW_ALL;
3452 }
3453
3454
3455 /* ---------- new tool button stuff ---------------------------------------- */
3456
3457 /* graphic position values for tool buttons */
3458 #define TOOL_BUTTON_YES_XPOS            2
3459 #define TOOL_BUTTON_YES_YPOS            250
3460 #define TOOL_BUTTON_YES_GFX_YPOS        0
3461 #define TOOL_BUTTON_YES_XSIZE           46
3462 #define TOOL_BUTTON_YES_YSIZE           28
3463 #define TOOL_BUTTON_NO_XPOS             52
3464 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
3465 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
3466 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
3467 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
3468 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
3469 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
3470 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
3471 #define TOOL_BUTTON_CONFIRM_XSIZE       96
3472 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
3473 #define TOOL_BUTTON_PLAYER_XSIZE        30
3474 #define TOOL_BUTTON_PLAYER_YSIZE        30
3475 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
3476 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3477 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3478 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3479 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3480                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3481 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3482                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3483 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3484                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3485 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3486                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3487 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3488                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3489 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3490                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3491 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3492                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3493 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3494                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3495
3496 static struct
3497 {
3498   int xpos, ypos;
3499   int x, y;
3500   int width, height;
3501   int gadget_id;
3502   char *infotext;
3503 } toolbutton_info[NUM_TOOL_BUTTONS] =
3504 {
3505   {
3506     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3507     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3508     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3509     TOOL_CTRL_ID_YES,
3510     "yes"
3511   },
3512   {
3513     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3514     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3515     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3516     TOOL_CTRL_ID_NO,
3517     "no"
3518   },
3519   {
3520     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3521     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3522     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3523     TOOL_CTRL_ID_CONFIRM,
3524     "confirm"
3525   },
3526   {
3527     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3528     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3529     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3530     TOOL_CTRL_ID_PLAYER_1,
3531     "player 1"
3532   },
3533   {
3534     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3535     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3536     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3537     TOOL_CTRL_ID_PLAYER_2,
3538     "player 2"
3539   },
3540   {
3541     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3542     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3543     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3544     TOOL_CTRL_ID_PLAYER_3,
3545     "player 3"
3546   },
3547   {
3548     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3549     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3550     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3551     TOOL_CTRL_ID_PLAYER_4,
3552     "player 4"
3553   }
3554 };
3555
3556 void CreateToolButtons()
3557 {
3558   int i;
3559
3560   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3561   {
3562     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3563     Bitmap *deco_bitmap = None;
3564     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3565     struct GadgetInfo *gi;
3566     unsigned long event_mask;
3567     int gd_xoffset, gd_yoffset;
3568     int gd_x1, gd_x2, gd_y;
3569     int id = i;
3570
3571     event_mask = GD_EVENT_RELEASED;
3572
3573     gd_xoffset = toolbutton_info[i].xpos;
3574     gd_yoffset = toolbutton_info[i].ypos;
3575     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3576     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3577     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3578
3579     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3580     {
3581       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3582
3583       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3584                            &deco_bitmap, &deco_x, &deco_y);
3585       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3586       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3587     }
3588
3589     gi = CreateGadget(GDI_CUSTOM_ID, id,
3590                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3591                       GDI_X, DX + toolbutton_info[i].x,
3592                       GDI_Y, DY + toolbutton_info[i].y,
3593                       GDI_WIDTH, toolbutton_info[i].width,
3594                       GDI_HEIGHT, toolbutton_info[i].height,
3595                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3596                       GDI_STATE, GD_BUTTON_UNPRESSED,
3597                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3598                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3599                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3600                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3601                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3602                       GDI_DECORATION_SHIFTING, 1, 1,
3603                       GDI_DIRECT_DRAW, FALSE,
3604                       GDI_EVENT_MASK, event_mask,
3605                       GDI_CALLBACK_ACTION, HandleToolButtons,
3606                       GDI_END);
3607
3608     if (gi == NULL)
3609       Error(ERR_EXIT, "cannot create gadget");
3610
3611     tool_gadget[id] = gi;
3612   }
3613 }
3614
3615 void FreeToolButtons()
3616 {
3617   int i;
3618
3619   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3620     FreeGadget(tool_gadget[i]);
3621 }
3622
3623 static void UnmapToolButtons()
3624 {
3625   int i;
3626
3627   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3628     UnmapGadget(tool_gadget[i]);
3629 }
3630
3631 static void HandleToolButtons(struct GadgetInfo *gi)
3632 {
3633   request_gadget_id = gi->custom_id;
3634 }
3635
3636 static struct Mapping_EM_to_RND_object
3637 {
3638   int element_em;
3639   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3640   boolean is_backside;                  /* backside of moving element */
3641
3642   int element_rnd;
3643   int action;
3644   int direction;
3645 }
3646 em_object_mapping_list[] =
3647 {
3648   {
3649     Xblank,                             TRUE,   FALSE,
3650     EL_EMPTY,                           -1, -1
3651   },
3652   {
3653     Yacid_splash_eB,                    FALSE,  FALSE,
3654     EL_ACID_SPLASH_RIGHT,               -1, -1
3655   },
3656   {
3657     Yacid_splash_wB,                    FALSE,  FALSE,
3658     EL_ACID_SPLASH_LEFT,                -1, -1
3659   },
3660
3661 #ifdef EM_ENGINE_BAD_ROLL
3662   {
3663     Xstone_force_e,                     FALSE,  FALSE,
3664     EL_ROCK,                            -1, MV_BIT_RIGHT
3665   },
3666   {
3667     Xstone_force_w,                     FALSE,  FALSE,
3668     EL_ROCK,                            -1, MV_BIT_LEFT
3669   },
3670   {
3671     Xnut_force_e,                       FALSE,  FALSE,
3672     EL_NUT,                             -1, MV_BIT_RIGHT
3673   },
3674   {
3675     Xnut_force_w,                       FALSE,  FALSE,
3676     EL_NUT,                             -1, MV_BIT_LEFT
3677   },
3678   {
3679     Xspring_force_e,                    FALSE,  FALSE,
3680     EL_SPRING,                          -1, MV_BIT_RIGHT
3681   },
3682   {
3683     Xspring_force_w,                    FALSE,  FALSE,
3684     EL_SPRING,                          -1, MV_BIT_LEFT
3685   },
3686   {
3687     Xemerald_force_e,                   FALSE,  FALSE,
3688     EL_EMERALD,                         -1, MV_BIT_RIGHT
3689   },
3690   {
3691     Xemerald_force_w,                   FALSE,  FALSE,
3692     EL_EMERALD,                         -1, MV_BIT_LEFT
3693   },
3694   {
3695     Xdiamond_force_e,                   FALSE,  FALSE,
3696     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3697   },
3698   {
3699     Xdiamond_force_w,                   FALSE,  FALSE,
3700     EL_DIAMOND,                         -1, MV_BIT_LEFT
3701   },
3702   {
3703     Xbomb_force_e,                      FALSE,  FALSE,
3704     EL_BOMB,                            -1, MV_BIT_RIGHT
3705   },
3706   {
3707     Xbomb_force_w,                      FALSE,  FALSE,
3708     EL_BOMB,                            -1, MV_BIT_LEFT
3709   },
3710 #endif  /* EM_ENGINE_BAD_ROLL */
3711
3712   {
3713     Xstone,                             TRUE,   FALSE,
3714     EL_ROCK,                            -1, -1
3715   },
3716   {
3717     Xstone_pause,                       FALSE,  FALSE,
3718     EL_ROCK,                            -1, -1
3719   },
3720   {
3721     Xstone_fall,                        FALSE,  FALSE,
3722     EL_ROCK,                            -1, -1
3723   },
3724   {
3725     Ystone_s,                           FALSE,  FALSE,
3726     EL_ROCK,                            ACTION_FALLING, -1
3727   },
3728   {
3729     Ystone_sB,                          FALSE,  TRUE,
3730     EL_ROCK,                            ACTION_FALLING, -1
3731   },
3732   {
3733     Ystone_e,                           FALSE,  FALSE,
3734     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3735   },
3736   {
3737     Ystone_eB,                          FALSE,  TRUE,
3738     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3739   },
3740   {
3741     Ystone_w,                           FALSE,  FALSE,
3742     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3743   },
3744   {
3745     Ystone_wB,                          FALSE,  TRUE,
3746     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3747   },
3748   {
3749     Xnut,                               TRUE,   FALSE,
3750     EL_NUT,                             -1, -1
3751   },
3752   {
3753     Xnut_pause,                         FALSE,  FALSE,
3754     EL_NUT,                             -1, -1
3755   },
3756   {
3757     Xnut_fall,                          FALSE,  FALSE,
3758     EL_NUT,                             -1, -1
3759   },
3760   {
3761     Ynut_s,                             FALSE,  FALSE,
3762     EL_NUT,                             ACTION_FALLING, -1
3763   },
3764   {
3765     Ynut_sB,                            FALSE,  TRUE,
3766     EL_NUT,                             ACTION_FALLING, -1
3767   },
3768   {
3769     Ynut_e,                             FALSE,  FALSE,
3770     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3771   },
3772   {
3773     Ynut_eB,                            FALSE,  TRUE,
3774     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3775   },
3776   {
3777     Ynut_w,                             FALSE,  FALSE,
3778     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3779   },
3780   {
3781     Ynut_wB,                            FALSE,  TRUE,
3782     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3783   },
3784   {
3785     Xbug_n,                             TRUE,   FALSE,
3786     EL_BUG_UP,                          -1, -1
3787   },
3788   {
3789     Xbug_e,                             TRUE,   FALSE,
3790     EL_BUG_RIGHT,                       -1, -1
3791   },
3792   {
3793     Xbug_s,                             TRUE,   FALSE,
3794     EL_BUG_DOWN,                        -1, -1
3795   },
3796   {
3797     Xbug_w,                             TRUE,   FALSE,
3798     EL_BUG_LEFT,                        -1, -1
3799   },
3800   {
3801     Xbug_gon,                           FALSE,  FALSE,
3802     EL_BUG_UP,                          -1, -1
3803   },
3804   {
3805     Xbug_goe,                           FALSE,  FALSE,
3806     EL_BUG_RIGHT,                       -1, -1
3807   },
3808   {
3809     Xbug_gos,                           FALSE,  FALSE,
3810     EL_BUG_DOWN,                        -1, -1
3811   },
3812   {
3813     Xbug_gow,                           FALSE,  FALSE,
3814     EL_BUG_LEFT,                        -1, -1
3815   },
3816   {
3817     Ybug_n,                             FALSE,  FALSE,
3818     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3819   },
3820   {
3821     Ybug_nB,                            FALSE,  TRUE,
3822     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3823   },
3824   {
3825     Ybug_e,                             FALSE,  FALSE,
3826     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3827   },
3828   {
3829     Ybug_eB,                            FALSE,  TRUE,
3830     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3831   },
3832   {
3833     Ybug_s,                             FALSE,  FALSE,
3834     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3835   },
3836   {
3837     Ybug_sB,                            FALSE,  TRUE,
3838     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3839   },
3840   {
3841     Ybug_w,                             FALSE,  FALSE,
3842     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3843   },
3844   {
3845     Ybug_wB,                            FALSE,  TRUE,
3846     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3847   },
3848   {
3849     Ybug_w_n,                           FALSE,  FALSE,
3850     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3851   },
3852   {
3853     Ybug_n_e,                           FALSE,  FALSE,
3854     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3855   },
3856   {
3857     Ybug_e_s,                           FALSE,  FALSE,
3858     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3859   },
3860   {
3861     Ybug_s_w,                           FALSE,  FALSE,
3862     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3863   },
3864   {
3865     Ybug_e_n,                           FALSE,  FALSE,
3866     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3867   },
3868   {
3869     Ybug_s_e,                           FALSE,  FALSE,
3870     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3871   },
3872   {
3873     Ybug_w_s,                           FALSE,  FALSE,
3874     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3875   },
3876   {
3877     Ybug_n_w,                           FALSE,  FALSE,
3878     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3879   },
3880   {
3881     Ybug_stone,                         FALSE,  FALSE,
3882     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3883   },
3884   {
3885     Ybug_spring,                        FALSE,  FALSE,
3886     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3887   },
3888   {
3889     Xtank_n,                            TRUE,   FALSE,
3890     EL_SPACESHIP_UP,                    -1, -1
3891   },
3892   {
3893     Xtank_e,                            TRUE,   FALSE,
3894     EL_SPACESHIP_RIGHT,                 -1, -1
3895   },
3896   {
3897     Xtank_s,                            TRUE,   FALSE,
3898     EL_SPACESHIP_DOWN,                  -1, -1
3899   },
3900   {
3901     Xtank_w,                            TRUE,   FALSE,
3902     EL_SPACESHIP_LEFT,                  -1, -1
3903   },
3904   {
3905     Xtank_gon,                          FALSE,  FALSE,
3906     EL_SPACESHIP_UP,                    -1, -1
3907   },
3908   {
3909     Xtank_goe,                          FALSE,  FALSE,
3910     EL_SPACESHIP_RIGHT,                 -1, -1
3911   },
3912   {
3913     Xtank_gos,                          FALSE,  FALSE,
3914     EL_SPACESHIP_DOWN,                  -1, -1
3915   },
3916   {
3917     Xtank_gow,                          FALSE,  FALSE,
3918     EL_SPACESHIP_LEFT,                  -1, -1
3919   },
3920   {
3921     Ytank_n,                            FALSE,  FALSE,
3922     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3923   },
3924   {
3925     Ytank_nB,                           FALSE,  TRUE,
3926     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3927   },
3928   {
3929     Ytank_e,                            FALSE,  FALSE,
3930     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3931   },
3932   {
3933     Ytank_eB,                           FALSE,  TRUE,
3934     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3935   },
3936   {
3937     Ytank_s,                            FALSE,  FALSE,
3938     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3939   },
3940   {
3941     Ytank_sB,                           FALSE,  TRUE,
3942     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3943   },
3944   {
3945     Ytank_w,                            FALSE,  FALSE,
3946     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3947   },
3948   {
3949     Ytank_wB,                           FALSE,  TRUE,
3950     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3951   },
3952   {
3953     Ytank_w_n,                          FALSE,  FALSE,
3954     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3955   },
3956   {
3957     Ytank_n_e,                          FALSE,  FALSE,
3958     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3959   },
3960   {
3961     Ytank_e_s,                          FALSE,  FALSE,
3962     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3963   },
3964   {
3965     Ytank_s_w,                          FALSE,  FALSE,
3966     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3967   },
3968   {
3969     Ytank_e_n,                          FALSE,  FALSE,
3970     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3971   },
3972   {
3973     Ytank_s_e,                          FALSE,  FALSE,
3974     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3975   },
3976   {
3977     Ytank_w_s,                          FALSE,  FALSE,
3978     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3979   },
3980   {
3981     Ytank_n_w,                          FALSE,  FALSE,
3982     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3983   },
3984   {
3985     Ytank_stone,                        FALSE,  FALSE,
3986     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3987   },
3988   {
3989     Ytank_spring,                       FALSE,  FALSE,
3990     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3991   },
3992   {
3993     Xandroid,                           TRUE,   FALSE,
3994     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3995   },
3996   {
3997     Xandroid_1_n,                       FALSE,  FALSE,
3998     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3999   },
4000   {
4001     Xandroid_2_n,                       FALSE,  FALSE,
4002     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4003   },
4004   {
4005     Xandroid_1_e,                       FALSE,  FALSE,
4006     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4007   },
4008   {
4009     Xandroid_2_e,                       FALSE,  FALSE,
4010     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4011   },
4012   {
4013     Xandroid_1_w,                       FALSE,  FALSE,
4014     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4015   },
4016   {
4017     Xandroid_2_w,                       FALSE,  FALSE,
4018     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4019   },
4020   {
4021     Xandroid_1_s,                       FALSE,  FALSE,
4022     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4023   },
4024   {
4025     Xandroid_2_s,                       FALSE,  FALSE,
4026     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4027   },
4028   {
4029     Yandroid_n,                         FALSE,  FALSE,
4030     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4031   },
4032   {
4033     Yandroid_nB,                        FALSE,  TRUE,
4034     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4035   },
4036   {
4037     Yandroid_ne,                        FALSE,  FALSE,
4038     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
4039   },
4040   {
4041     Yandroid_neB,                       FALSE,  TRUE,
4042     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
4043   },
4044   {
4045     Yandroid_e,                         FALSE,  FALSE,
4046     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4047   },
4048   {
4049     Yandroid_eB,                        FALSE,  TRUE,
4050     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4051   },
4052   {
4053     Yandroid_se,                        FALSE,  FALSE,
4054     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
4055   },
4056   {
4057     Yandroid_seB,                       FALSE,  TRUE,
4058     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4059   },
4060   {
4061     Yandroid_s,                         FALSE,  FALSE,
4062     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4063   },
4064   {
4065     Yandroid_sB,                        FALSE,  TRUE,
4066     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4067   },
4068   {
4069     Yandroid_sw,                        FALSE,  FALSE,
4070     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
4071   },
4072   {
4073     Yandroid_swB,                       FALSE,  TRUE,
4074     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
4075   },
4076   {
4077     Yandroid_w,                         FALSE,  FALSE,
4078     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4079   },
4080   {
4081     Yandroid_wB,                        FALSE,  TRUE,
4082     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4083   },
4084   {
4085     Yandroid_nw,                        FALSE,  FALSE,
4086     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
4087   },
4088   {
4089     Yandroid_nwB,                       FALSE,  TRUE,
4090     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
4091   },
4092   {
4093     Xspring,                            TRUE,   FALSE,
4094     EL_SPRING,                          -1, -1
4095   },
4096   {
4097     Xspring_pause,                      FALSE,  FALSE,
4098     EL_SPRING,                          -1, -1
4099   },
4100   {
4101     Xspring_e,                          FALSE,  FALSE,
4102     EL_SPRING,                          -1, -1
4103   },
4104   {
4105     Xspring_w,                          FALSE,  FALSE,
4106     EL_SPRING,                          -1, -1
4107   },
4108   {
4109     Xspring_fall,                       FALSE,  FALSE,
4110     EL_SPRING,                          -1, -1
4111   },
4112   {
4113     Yspring_s,                          FALSE,  FALSE,
4114     EL_SPRING,                          ACTION_FALLING, -1
4115   },
4116   {
4117     Yspring_sB,                         FALSE,  TRUE,
4118     EL_SPRING,                          ACTION_FALLING, -1
4119   },
4120   {
4121     Yspring_e,                          FALSE,  FALSE,
4122     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4123   },
4124   {
4125     Yspring_eB,                         FALSE,  TRUE,
4126     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4127   },
4128   {
4129     Yspring_w,                          FALSE,  FALSE,
4130     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4131   },
4132   {
4133     Yspring_wB,                         FALSE,  TRUE,
4134     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4135   },
4136   {
4137     Yspring_kill_e,                     FALSE,  FALSE,
4138     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4139   },
4140   {
4141     Yspring_kill_eB,                    FALSE,  TRUE,
4142     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4143   },
4144   {
4145     Yspring_kill_w,                     FALSE,  FALSE,
4146     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4147   },
4148   {
4149     Yspring_kill_wB,                    FALSE,  TRUE,
4150     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4151   },
4152   {
4153     Xeater_n,                           TRUE,   FALSE,
4154     EL_YAMYAM_UP,                       -1, -1
4155   },
4156   {
4157     Xeater_e,                           TRUE,   FALSE,
4158     EL_YAMYAM_RIGHT,                    -1, -1
4159   },
4160   {
4161     Xeater_w,                           TRUE,   FALSE,
4162     EL_YAMYAM_LEFT,                     -1, -1
4163   },
4164   {
4165     Xeater_s,                           TRUE,   FALSE,
4166     EL_YAMYAM_DOWN,                     -1, -1
4167   },
4168   {
4169     Yeater_n,                           FALSE,  FALSE,
4170     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4171   },
4172   {
4173     Yeater_nB,                          FALSE,  TRUE,
4174     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4175   },
4176   {
4177     Yeater_e,                           FALSE,  FALSE,
4178     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4179   },
4180   {
4181     Yeater_eB,                          FALSE,  TRUE,
4182     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4183   },
4184   {
4185     Yeater_s,                           FALSE,  FALSE,
4186     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4187   },
4188   {
4189     Yeater_sB,                          FALSE,  TRUE,
4190     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4191   },
4192   {
4193     Yeater_w,                           FALSE,  FALSE,
4194     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4195   },
4196   {
4197     Yeater_wB,                          FALSE,  TRUE,
4198     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4199   },
4200   {
4201     Yeater_stone,                       FALSE,  FALSE,
4202     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
4203   },
4204   {
4205     Yeater_spring,                      FALSE,  FALSE,
4206     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
4207   },
4208   {
4209     Xalien,                             TRUE,   FALSE,
4210     EL_ROBOT,                           -1, -1
4211   },
4212   {
4213     Xalien_pause,                       FALSE,  FALSE,
4214     EL_ROBOT,                           -1, -1
4215   },
4216   {
4217     Yalien_n,                           FALSE,  FALSE,
4218     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4219   },
4220   {
4221     Yalien_nB,                          FALSE,  TRUE,
4222     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4223   },
4224   {
4225     Yalien_e,                           FALSE,  FALSE,
4226     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4227   },
4228   {
4229     Yalien_eB,                          FALSE,  TRUE,
4230     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4231   },
4232   {
4233     Yalien_s,                           FALSE,  FALSE,
4234     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4235   },
4236   {
4237     Yalien_sB,                          FALSE,  TRUE,
4238     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4239   },
4240   {
4241     Yalien_w,                           FALSE,  FALSE,
4242     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4243   },
4244   {
4245     Yalien_wB,                          FALSE,  TRUE,
4246     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4247   },
4248   {
4249     Yalien_stone,                       FALSE,  FALSE,
4250     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
4251   },
4252   {
4253     Yalien_spring,                      FALSE,  FALSE,
4254     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
4255   },
4256   {
4257     Xemerald,                           TRUE,   FALSE,
4258     EL_EMERALD,                         -1, -1
4259   },
4260   {
4261     Xemerald_pause,                     FALSE,  FALSE,
4262     EL_EMERALD,                         -1, -1
4263   },
4264   {
4265     Xemerald_fall,                      FALSE,  FALSE,
4266     EL_EMERALD,                         -1, -1
4267   },
4268   {
4269     Xemerald_shine,                     FALSE,  FALSE,
4270     EL_EMERALD,                         ACTION_TWINKLING, -1
4271   },
4272   {
4273     Yemerald_s,                         FALSE,  FALSE,
4274     EL_EMERALD,                         ACTION_FALLING, -1
4275   },
4276   {
4277     Yemerald_sB,                        FALSE,  TRUE,
4278     EL_EMERALD,                         ACTION_FALLING, -1
4279   },
4280   {
4281     Yemerald_e,                         FALSE,  FALSE,
4282     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4283   },
4284   {
4285     Yemerald_eB,                        FALSE,  TRUE,
4286     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4287   },
4288   {
4289     Yemerald_w,                         FALSE,  FALSE,
4290     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4291   },
4292   {
4293     Yemerald_wB,                        FALSE,  TRUE,
4294     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4295   },
4296   {
4297     Yemerald_eat,                       FALSE,  FALSE,
4298     EL_EMERALD,                         ACTION_COLLECTING, -1
4299   },
4300   {
4301     Yemerald_stone,                     FALSE,  FALSE,
4302     EL_NUT,                             ACTION_BREAKING, -1
4303   },
4304   {
4305     Xdiamond,                           TRUE,   FALSE,
4306     EL_DIAMOND,                         -1, -1
4307   },
4308   {
4309     Xdiamond_pause,                     FALSE,  FALSE,
4310     EL_DIAMOND,                         -1, -1
4311   },
4312   {
4313     Xdiamond_fall,                      FALSE,  FALSE,
4314     EL_DIAMOND,                         -1, -1
4315   },
4316   {
4317     Xdiamond_shine,                     FALSE,  FALSE,
4318     EL_DIAMOND,                         ACTION_TWINKLING, -1
4319   },
4320   {
4321     Ydiamond_s,                         FALSE,  FALSE,
4322     EL_DIAMOND,                         ACTION_FALLING, -1
4323   },
4324   {
4325     Ydiamond_sB,                        FALSE,  TRUE,
4326     EL_DIAMOND,                         ACTION_FALLING, -1
4327   },
4328   {
4329     Ydiamond_e,                         FALSE,  FALSE,
4330     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4331   },
4332   {
4333     Ydiamond_eB,                        FALSE,  TRUE,
4334     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4335   },
4336   {
4337     Ydiamond_w,                         FALSE,  FALSE,
4338     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4339   },
4340   {
4341     Ydiamond_wB,                        FALSE,  TRUE,
4342     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4343   },
4344   {
4345     Ydiamond_eat,                       FALSE,  FALSE,
4346     EL_DIAMOND,                         ACTION_COLLECTING, -1
4347   },
4348   {
4349     Ydiamond_stone,                     FALSE,  FALSE,
4350     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
4351   },
4352   {
4353     Xdrip_fall,                         TRUE,   FALSE,
4354     EL_AMOEBA_DROP,                     -1, -1
4355   },
4356   {
4357     Xdrip_stretch,                      FALSE,  FALSE,
4358     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4359   },
4360   {
4361     Xdrip_stretchB,                     FALSE,  TRUE,
4362     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4363   },
4364   {
4365     Xdrip_eat,                          FALSE,  FALSE,
4366     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
4367   },
4368   {
4369     Ydrip_s1,                           FALSE,  FALSE,
4370     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4371   },
4372   {
4373     Ydrip_s1B,                          FALSE,  TRUE,
4374     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4375   },
4376   {
4377     Ydrip_s2,                           FALSE,  FALSE,
4378     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4379   },
4380   {
4381     Ydrip_s2B,                          FALSE,  TRUE,
4382     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4383   },
4384   {
4385     Xbomb,                              TRUE,   FALSE,
4386     EL_BOMB,                            -1, -1
4387   },
4388   {
4389     Xbomb_pause,                        FALSE,  FALSE,
4390     EL_BOMB,                            -1, -1
4391   },
4392   {
4393     Xbomb_fall,                         FALSE,  FALSE,
4394     EL_BOMB,                            -1, -1
4395   },
4396   {
4397     Ybomb_s,                            FALSE,  FALSE,
4398     EL_BOMB,                            ACTION_FALLING, -1
4399   },
4400   {
4401     Ybomb_sB,                           FALSE,  TRUE,
4402     EL_BOMB,                            ACTION_FALLING, -1
4403   },
4404   {
4405     Ybomb_e,                            FALSE,  FALSE,
4406     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4407   },
4408   {
4409     Ybomb_eB,                           FALSE,  TRUE,
4410     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4411   },
4412   {
4413     Ybomb_w,                            FALSE,  FALSE,
4414     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4415   },
4416   {
4417     Ybomb_wB,                           FALSE,  TRUE,
4418     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4419   },
4420   {
4421     Ybomb_eat,                          FALSE,  FALSE,
4422     EL_BOMB,                            ACTION_ACTIVATING, -1
4423   },
4424   {
4425     Xballoon,                           TRUE,   FALSE,
4426     EL_BALLOON,                         -1, -1
4427   },
4428   {
4429     Yballoon_n,                         FALSE,  FALSE,
4430     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4431   },
4432   {
4433     Yballoon_nB,                        FALSE,  TRUE,
4434     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4435   },
4436   {
4437     Yballoon_e,                         FALSE,  FALSE,
4438     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4439   },
4440   {
4441     Yballoon_eB,                        FALSE,  TRUE,
4442     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4443   },
4444   {
4445     Yballoon_s,                         FALSE,  FALSE,
4446     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4447   },
4448   {
4449     Yballoon_sB,                        FALSE,  TRUE,
4450     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4451   },
4452   {
4453     Yballoon_w,                         FALSE,  FALSE,
4454     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4455   },
4456   {
4457     Yballoon_wB,                        FALSE,  TRUE,
4458     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4459   },
4460   {
4461     Xgrass,                             TRUE,   FALSE,
4462     EL_EMC_GRASS,                       -1, -1
4463   },
4464   {
4465     Ygrass_nB,                          FALSE,  FALSE,
4466     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
4467   },
4468   {
4469     Ygrass_eB,                          FALSE,  FALSE,
4470     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
4471   },
4472   {
4473     Ygrass_sB,                          FALSE,  FALSE,
4474     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
4475   },
4476   {
4477     Ygrass_wB,                          FALSE,  FALSE,
4478     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4479   },
4480   {
4481     Xdirt,                              TRUE,   FALSE,
4482     EL_SAND,                            -1, -1
4483   },
4484   {
4485     Ydirt_nB,                           FALSE,  FALSE,
4486     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4487   },
4488   {
4489     Ydirt_eB,                           FALSE,  FALSE,
4490     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4491   },
4492   {
4493     Ydirt_sB,                           FALSE,  FALSE,
4494     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4495   },
4496   {
4497     Ydirt_wB,                           FALSE,  FALSE,
4498     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4499   },
4500   {
4501     Xacid_ne,                           TRUE,   FALSE,
4502     EL_ACID_POOL_TOPRIGHT,              -1, -1
4503   },
4504   {
4505     Xacid_se,                           TRUE,   FALSE,
4506     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4507   },
4508   {
4509     Xacid_s,                            TRUE,   FALSE,
4510     EL_ACID_POOL_BOTTOM,                -1, -1
4511   },
4512   {
4513     Xacid_sw,                           TRUE,   FALSE,
4514     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4515   },
4516   {
4517     Xacid_nw,                           TRUE,   FALSE,
4518     EL_ACID_POOL_TOPLEFT,               -1, -1
4519   },
4520   {
4521     Xacid_1,                            TRUE,   FALSE,
4522     EL_ACID,                            -1, -1
4523   },
4524   {
4525     Xacid_2,                            FALSE,  FALSE,
4526     EL_ACID,                            -1, -1
4527   },
4528   {
4529     Xacid_3,                            FALSE,  FALSE,
4530     EL_ACID,                            -1, -1
4531   },
4532   {
4533     Xacid_4,                            FALSE,  FALSE,
4534     EL_ACID,                            -1, -1
4535   },
4536   {
4537     Xacid_5,                            FALSE,  FALSE,
4538     EL_ACID,                            -1, -1
4539   },
4540   {
4541     Xacid_6,                            FALSE,  FALSE,
4542     EL_ACID,                            -1, -1
4543   },
4544   {
4545     Xacid_7,                            FALSE,  FALSE,
4546     EL_ACID,                            -1, -1
4547   },
4548   {
4549     Xacid_8,                            FALSE,  FALSE,
4550     EL_ACID,                            -1, -1
4551   },
4552   {
4553     Xball_1,                            TRUE,   FALSE,
4554     EL_EMC_MAGIC_BALL,                  -1, -1
4555   },
4556   {
4557     Xball_1B,                           FALSE,  FALSE,
4558     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4559   },
4560   {
4561     Xball_2,                            FALSE,  FALSE,
4562     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4563   },
4564   {
4565     Xball_2B,                           FALSE,  FALSE,
4566     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4567   },
4568   {
4569     Yball_eat,                          FALSE,  FALSE,
4570     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4571   },
4572   {
4573     Ykey_1_eat,                         FALSE,  FALSE,
4574     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4575   },
4576   {
4577     Ykey_2_eat,                         FALSE,  FALSE,
4578     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4579   },
4580   {
4581     Ykey_3_eat,                         FALSE,  FALSE,
4582     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4583   },
4584   {
4585     Ykey_4_eat,                         FALSE,  FALSE,
4586     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4587   },
4588   {
4589     Ykey_5_eat,                         FALSE,  FALSE,
4590     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4591   },
4592   {
4593     Ykey_6_eat,                         FALSE,  FALSE,
4594     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4595   },
4596   {
4597     Ykey_7_eat,                         FALSE,  FALSE,
4598     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4599   },
4600   {
4601     Ykey_8_eat,                         FALSE,  FALSE,
4602     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4603   },
4604   {
4605     Ylenses_eat,                        FALSE,  FALSE,
4606     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4607   },
4608   {
4609     Ymagnify_eat,                       FALSE,  FALSE,
4610     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4611   },
4612   {
4613     Ygrass_eat,                         FALSE,  FALSE,
4614     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4615   },
4616   {
4617     Ydirt_eat,                          FALSE,  FALSE,
4618     EL_SAND,                            ACTION_SNAPPING, -1
4619   },
4620   {
4621     Xgrow_ns,                           TRUE,   FALSE,
4622     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4623   },
4624   {
4625     Ygrow_ns_eat,                       FALSE,  FALSE,
4626     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4627   },
4628   {
4629     Xgrow_ew,                           TRUE,   FALSE,
4630     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4631   },
4632   {
4633     Ygrow_ew_eat,                       FALSE,  FALSE,
4634     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4635   },
4636   {
4637     Xwonderwall,                        TRUE,   FALSE,
4638     EL_MAGIC_WALL,                      -1, -1
4639   },
4640   {
4641     XwonderwallB,                       FALSE,  FALSE,
4642     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4643   },
4644   {
4645     Xamoeba_1,                          TRUE,   FALSE,
4646     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4647   },
4648   {
4649     Xamoeba_2,                          FALSE,  FALSE,
4650     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4651   },
4652   {
4653     Xamoeba_3,                          FALSE,  FALSE,
4654     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4655   },
4656   {
4657     Xamoeba_4,                          FALSE,  FALSE,
4658     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4659   },
4660   {
4661     Xamoeba_5,                          TRUE,   FALSE,
4662     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4663   },
4664   {
4665     Xamoeba_6,                          FALSE,  FALSE,
4666     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4667   },
4668   {
4669     Xamoeba_7,                          FALSE,  FALSE,
4670     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4671   },
4672   {
4673     Xamoeba_8,                          FALSE,  FALSE,
4674     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4675   },
4676   {
4677     Xdoor_1,                            TRUE,   FALSE,
4678     EL_EM_GATE_1,                       -1, -1
4679   },
4680   {
4681     Xdoor_2,                            TRUE,   FALSE,
4682     EL_EM_GATE_2,                       -1, -1
4683   },
4684   {
4685     Xdoor_3,                            TRUE,   FALSE,
4686     EL_EM_GATE_3,                       -1, -1
4687   },
4688   {
4689     Xdoor_4,                            TRUE,   FALSE,
4690     EL_EM_GATE_4,                       -1, -1
4691   },
4692   {
4693     Xdoor_5,                            TRUE,   FALSE,
4694     EL_EMC_GATE_5,                      -1, -1
4695   },
4696   {
4697     Xdoor_6,                            TRUE,   FALSE,
4698     EL_EMC_GATE_6,                      -1, -1
4699   },
4700   {
4701     Xdoor_7,                            TRUE,   FALSE,
4702     EL_EMC_GATE_7,                      -1, -1
4703   },
4704   {
4705     Xdoor_8,                            TRUE,   FALSE,
4706     EL_EMC_GATE_8,                      -1, -1
4707   },
4708   {
4709     Xkey_1,                             TRUE,   FALSE,
4710     EL_EM_KEY_1,                        -1, -1
4711   },
4712   {
4713     Xkey_2,                             TRUE,   FALSE,
4714     EL_EM_KEY_2,                        -1, -1
4715   },
4716   {
4717     Xkey_3,                             TRUE,   FALSE,
4718     EL_EM_KEY_3,                        -1, -1
4719   },
4720   {
4721     Xkey_4,                             TRUE,   FALSE,
4722     EL_EM_KEY_4,                        -1, -1
4723   },
4724   {
4725     Xkey_5,                             TRUE,   FALSE,
4726     EL_EMC_KEY_5,                       -1, -1
4727   },
4728   {
4729     Xkey_6,                             TRUE,   FALSE,
4730     EL_EMC_KEY_6,                       -1, -1
4731   },
4732   {
4733     Xkey_7,                             TRUE,   FALSE,
4734     EL_EMC_KEY_7,                       -1, -1
4735   },
4736   {
4737     Xkey_8,                             TRUE,   FALSE,
4738     EL_EMC_KEY_8,                       -1, -1
4739   },
4740   {
4741     Xwind_n,                            TRUE,   FALSE,
4742     EL_BALLOON_SWITCH_UP,               -1, -1
4743   },
4744   {
4745     Xwind_e,                            TRUE,   FALSE,
4746     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4747   },
4748   {
4749     Xwind_s,                            TRUE,   FALSE,
4750     EL_BALLOON_SWITCH_DOWN,             -1, -1
4751   },
4752   {
4753     Xwind_w,                            TRUE,   FALSE,
4754     EL_BALLOON_SWITCH_LEFT,             -1, -1
4755   },
4756   {
4757     Xwind_nesw,                         TRUE,   FALSE,
4758     EL_BALLOON_SWITCH_ANY,              -1, -1
4759   },
4760   {
4761     Xwind_stop,                         TRUE,   FALSE,
4762     EL_BALLOON_SWITCH_NONE,             -1, -1
4763   },
4764   {
4765     Xexit,                              TRUE,   FALSE,
4766     EL_EM_EXIT_CLOSED,                  -1, -1
4767   },
4768   {
4769     Xexit_1,                            TRUE,   FALSE,
4770     EL_EM_EXIT_OPEN,                    -1, -1
4771   },
4772   {
4773     Xexit_2,                            FALSE,  FALSE,
4774     EL_EM_EXIT_OPEN,                    -1, -1
4775   },
4776   {
4777     Xexit_3,                            FALSE,  FALSE,
4778     EL_EM_EXIT_OPEN,                    -1, -1
4779   },
4780   {
4781     Xdynamite,                          TRUE,   FALSE,
4782     EL_EM_DYNAMITE,                     -1, -1
4783   },
4784   {
4785     Ydynamite_eat,                      FALSE,  FALSE,
4786     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4787   },
4788   {
4789     Xdynamite_1,                        TRUE,   FALSE,
4790     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4791   },
4792   {
4793     Xdynamite_2,                        FALSE,  FALSE,
4794     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4795   },
4796   {
4797     Xdynamite_3,                        FALSE,  FALSE,
4798     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4799   },
4800   {
4801     Xdynamite_4,                        FALSE,  FALSE,
4802     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4803   },
4804   {
4805     Xbumper,                            TRUE,   FALSE,
4806     EL_EMC_SPRING_BUMPER,               -1, -1
4807   },
4808   {
4809     XbumperB,                           FALSE,  FALSE,
4810     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4811   },
4812   {
4813     Xwheel,                             TRUE,   FALSE,
4814     EL_ROBOT_WHEEL,                     -1, -1
4815   },
4816   {
4817     XwheelB,                            FALSE,  FALSE,
4818     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4819   },
4820   {
4821     Xswitch,                            TRUE,   FALSE,
4822     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4823   },
4824   {
4825     XswitchB,                           FALSE,  FALSE,
4826     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4827   },
4828   {
4829     Xsand,                              TRUE,   FALSE,
4830     EL_QUICKSAND_EMPTY,                 -1, -1
4831   },
4832   {
4833     Xsand_stone,                        TRUE,   FALSE,
4834     EL_QUICKSAND_FULL,                  -1, -1
4835   },
4836   {
4837     Xsand_stonein_1,                    FALSE,  TRUE,
4838     EL_ROCK,                            ACTION_FILLING, -1
4839   },
4840   {
4841     Xsand_stonein_2,                    FALSE,  TRUE,
4842     EL_ROCK,                            ACTION_FILLING, -1
4843   },
4844   {
4845     Xsand_stonein_3,                    FALSE,  TRUE,
4846     EL_ROCK,                            ACTION_FILLING, -1
4847   },
4848   {
4849     Xsand_stonein_4,                    FALSE,  TRUE,
4850     EL_ROCK,                            ACTION_FILLING, -1
4851   },
4852   {
4853     Xsand_stonesand_1,                  FALSE,  FALSE,
4854     EL_QUICKSAND_FULL,                  -1, -1
4855   },
4856   {
4857     Xsand_stonesand_2,                  FALSE,  FALSE,
4858     EL_QUICKSAND_FULL,                  -1, -1
4859   },
4860   {
4861     Xsand_stonesand_3,                  FALSE,  FALSE,
4862     EL_QUICKSAND_FULL,                  -1, -1
4863   },
4864   {
4865     Xsand_stonesand_4,                  FALSE,  FALSE,
4866     EL_QUICKSAND_FULL,                  -1, -1
4867   },
4868   {
4869     Xsand_stoneout_1,                   FALSE,  FALSE,
4870     EL_ROCK,                            ACTION_EMPTYING, -1
4871   },
4872   {
4873     Xsand_stoneout_2,                   FALSE,  FALSE,
4874     EL_ROCK,                            ACTION_EMPTYING, -1
4875   },
4876   {
4877     Xsand_sandstone_1,                  FALSE,  FALSE,
4878     EL_QUICKSAND_FULL,                  -1, -1
4879   },
4880   {
4881     Xsand_sandstone_2,                  FALSE,  FALSE,
4882     EL_QUICKSAND_FULL,                  -1, -1
4883   },
4884   {
4885     Xsand_sandstone_3,                  FALSE,  FALSE,
4886     EL_QUICKSAND_FULL,                  -1, -1
4887   },
4888   {
4889     Xsand_sandstone_4,                  FALSE,  FALSE,
4890     EL_QUICKSAND_FULL,                  -1, -1
4891   },
4892   {
4893     Xplant,                             TRUE,   FALSE,
4894     EL_EMC_PLANT,                       -1, -1
4895   },
4896   {
4897     Yplant,                             FALSE,  FALSE,
4898     EL_EMC_PLANT,                       -1, -1
4899   },
4900   {
4901     Xlenses,                            TRUE,   FALSE,
4902     EL_EMC_LENSES,                      -1, -1
4903   },
4904   {
4905     Xmagnify,                           TRUE,   FALSE,
4906     EL_EMC_MAGNIFIER,                   -1, -1
4907   },
4908   {
4909     Xdripper,                           TRUE,   FALSE,
4910     EL_EMC_DRIPPER,                     -1, -1
4911   },
4912   {
4913     XdripperB,                          FALSE,  FALSE,
4914     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4915   },
4916   {
4917     Xfake_blank,                        TRUE,   FALSE,
4918     EL_INVISIBLE_WALL,                  -1, -1
4919   },
4920   {
4921     Xfake_blankB,                       FALSE,  FALSE,
4922     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4923   },
4924   {
4925     Xfake_grass,                        TRUE,   FALSE,
4926     EL_EMC_FAKE_GRASS,                  -1, -1
4927   },
4928   {
4929     Xfake_grassB,                       FALSE,  FALSE,
4930     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4931   },
4932   {
4933     Xfake_door_1,                       TRUE,   FALSE,
4934     EL_EM_GATE_1_GRAY,                  -1, -1
4935   },
4936   {
4937     Xfake_door_2,                       TRUE,   FALSE,
4938     EL_EM_GATE_2_GRAY,                  -1, -1
4939   },
4940   {
4941     Xfake_door_3,                       TRUE,   FALSE,
4942     EL_EM_GATE_3_GRAY,                  -1, -1
4943   },
4944   {
4945     Xfake_door_4,                       TRUE,   FALSE,
4946     EL_EM_GATE_4_GRAY,                  -1, -1
4947   },
4948   {
4949     Xfake_door_5,                       TRUE,   FALSE,
4950     EL_EMC_GATE_5_GRAY,                 -1, -1
4951   },
4952   {
4953     Xfake_door_6,                       TRUE,   FALSE,
4954     EL_EMC_GATE_6_GRAY,                 -1, -1
4955   },
4956   {
4957     Xfake_door_7,                       TRUE,   FALSE,
4958     EL_EMC_GATE_7_GRAY,                 -1, -1
4959   },
4960   {
4961     Xfake_door_8,                       TRUE,   FALSE,
4962     EL_EMC_GATE_8_GRAY,                 -1, -1
4963   },
4964   {
4965     Xfake_acid_1,                       TRUE,   FALSE,
4966     EL_EMC_FAKE_ACID,                   -1, -1
4967   },
4968   {
4969     Xfake_acid_2,                       FALSE,  FALSE,
4970     EL_EMC_FAKE_ACID,                   -1, -1
4971   },
4972   {
4973     Xfake_acid_3,                       FALSE,  FALSE,
4974     EL_EMC_FAKE_ACID,                   -1, -1
4975   },
4976   {
4977     Xfake_acid_4,                       FALSE,  FALSE,
4978     EL_EMC_FAKE_ACID,                   -1, -1
4979   },
4980   {
4981     Xfake_acid_5,                       FALSE,  FALSE,
4982     EL_EMC_FAKE_ACID,                   -1, -1
4983   },
4984   {
4985     Xfake_acid_6,                       FALSE,  FALSE,
4986     EL_EMC_FAKE_ACID,                   -1, -1
4987   },
4988   {
4989     Xfake_acid_7,                       FALSE,  FALSE,
4990     EL_EMC_FAKE_ACID,                   -1, -1
4991   },
4992   {
4993     Xfake_acid_8,                       FALSE,  FALSE,
4994     EL_EMC_FAKE_ACID,                   -1, -1
4995   },
4996   {
4997     Xsteel_1,                           TRUE,   FALSE,
4998     EL_STEELWALL,                       -1, -1
4999   },
5000   {
5001     Xsteel_2,                           TRUE,   FALSE,
5002     EL_EMC_STEELWALL_2,                 -1, -1
5003   },
5004   {
5005     Xsteel_3,                           TRUE,   FALSE,
5006     EL_EMC_STEELWALL_3,                 -1, -1
5007   },
5008   {
5009     Xsteel_4,                           TRUE,   FALSE,
5010     EL_EMC_STEELWALL_4,                 -1, -1
5011   },
5012   {
5013     Xwall_1,                            TRUE,   FALSE,
5014     EL_WALL,                            -1, -1
5015   },
5016   {
5017     Xwall_2,                            TRUE,   FALSE,
5018     EL_EMC_WALL_14,                     -1, -1
5019   },
5020   {
5021     Xwall_3,                            TRUE,   FALSE,
5022     EL_EMC_WALL_15,                     -1, -1
5023   },
5024   {
5025     Xwall_4,                            TRUE,   FALSE,
5026     EL_EMC_WALL_16,                     -1, -1
5027   },
5028   {
5029     Xround_wall_1,                      TRUE,   FALSE,
5030     EL_WALL_SLIPPERY,                   -1, -1
5031   },
5032   {
5033     Xround_wall_2,                      TRUE,   FALSE,
5034     EL_EMC_WALL_SLIPPERY_2,             -1, -1
5035   },
5036   {
5037     Xround_wall_3,                      TRUE,   FALSE,
5038     EL_EMC_WALL_SLIPPERY_3,             -1, -1
5039   },
5040   {
5041     Xround_wall_4,                      TRUE,   FALSE,
5042     EL_EMC_WALL_SLIPPERY_4,             -1, -1
5043   },
5044   {
5045     Xdecor_1,                           TRUE,   FALSE,
5046     EL_EMC_WALL_8,                      -1, -1
5047   },
5048   {
5049     Xdecor_2,                           TRUE,   FALSE,
5050     EL_EMC_WALL_6,                      -1, -1
5051   },
5052   {
5053     Xdecor_3,                           TRUE,   FALSE,
5054     EL_EMC_WALL_4,                      -1, -1
5055   },
5056   {
5057     Xdecor_4,                           TRUE,   FALSE,
5058     EL_EMC_WALL_7,                      -1, -1
5059   },
5060   {
5061     Xdecor_5,                           TRUE,   FALSE,
5062     EL_EMC_WALL_5,                      -1, -1
5063   },
5064   {
5065     Xdecor_6,                           TRUE,   FALSE,
5066     EL_EMC_WALL_9,                      -1, -1
5067   },
5068   {
5069     Xdecor_7,                           TRUE,   FALSE,
5070     EL_EMC_WALL_10,                     -1, -1
5071   },
5072   {
5073     Xdecor_8,                           TRUE,   FALSE,
5074     EL_EMC_WALL_1,                      -1, -1
5075   },
5076   {
5077     Xdecor_9,                           TRUE,   FALSE,
5078     EL_EMC_WALL_2,                      -1, -1
5079   },
5080   {
5081     Xdecor_10,                          TRUE,   FALSE,
5082     EL_EMC_WALL_3,                      -1, -1
5083   },
5084   {
5085     Xdecor_11,                          TRUE,   FALSE,
5086     EL_EMC_WALL_11,                     -1, -1
5087   },
5088   {
5089     Xdecor_12,                          TRUE,   FALSE,
5090     EL_EMC_WALL_12,                     -1, -1
5091   },
5092   {
5093     Xalpha_0,                           TRUE,   FALSE,
5094     EL_CHAR('0'),                       -1, -1
5095   },
5096   {
5097     Xalpha_1,                           TRUE,   FALSE,
5098     EL_CHAR('1'),                       -1, -1
5099   },
5100   {
5101     Xalpha_2,                           TRUE,   FALSE,
5102     EL_CHAR('2'),                       -1, -1
5103   },
5104   {
5105     Xalpha_3,                           TRUE,   FALSE,
5106     EL_CHAR('3'),                       -1, -1
5107   },
5108   {
5109     Xalpha_4,                           TRUE,   FALSE,
5110     EL_CHAR('4'),                       -1, -1
5111   },
5112   {
5113     Xalpha_5,                           TRUE,   FALSE,
5114     EL_CHAR('5'),                       -1, -1
5115   },
5116   {
5117     Xalpha_6,                           TRUE,   FALSE,
5118     EL_CHAR('6'),                       -1, -1
5119   },
5120   {
5121     Xalpha_7,                           TRUE,   FALSE,
5122     EL_CHAR('7'),                       -1, -1
5123   },
5124   {
5125     Xalpha_8,                           TRUE,   FALSE,
5126     EL_CHAR('8'),                       -1, -1
5127   },
5128   {
5129     Xalpha_9,                           TRUE,   FALSE,
5130     EL_CHAR('9'),                       -1, -1
5131   },
5132   {
5133     Xalpha_excla,                       TRUE,   FALSE,
5134     EL_CHAR('!'),                       -1, -1
5135   },
5136   {
5137     Xalpha_quote,                       TRUE,   FALSE,
5138     EL_CHAR('"'),                       -1, -1
5139   },
5140   {
5141     Xalpha_comma,                       TRUE,   FALSE,
5142     EL_CHAR(','),                       -1, -1
5143   },
5144   {
5145     Xalpha_minus,                       TRUE,   FALSE,
5146     EL_CHAR('-'),                       -1, -1
5147   },
5148   {
5149     Xalpha_perio,                       TRUE,   FALSE,
5150     EL_CHAR('.'),                       -1, -1
5151   },
5152   {
5153     Xalpha_colon,                       TRUE,   FALSE,
5154     EL_CHAR(':'),                       -1, -1
5155   },
5156   {
5157     Xalpha_quest,                       TRUE,   FALSE,
5158     EL_CHAR('?'),                       -1, -1
5159   },
5160   {
5161     Xalpha_a,                           TRUE,   FALSE,
5162     EL_CHAR('A'),                       -1, -1
5163   },
5164   {
5165     Xalpha_b,                           TRUE,   FALSE,
5166     EL_CHAR('B'),                       -1, -1
5167   },
5168   {
5169     Xalpha_c,                           TRUE,   FALSE,
5170     EL_CHAR('C'),                       -1, -1
5171   },
5172   {
5173     Xalpha_d,                           TRUE,   FALSE,
5174     EL_CHAR('D'),                       -1, -1
5175   },
5176   {
5177     Xalpha_e,                           TRUE,   FALSE,
5178     EL_CHAR('E'),                       -1, -1
5179   },
5180   {
5181     Xalpha_f,                           TRUE,   FALSE,
5182     EL_CHAR('F'),                       -1, -1
5183   },
5184   {
5185     Xalpha_g,                           TRUE,   FALSE,
5186     EL_CHAR('G'),                       -1, -1
5187   },
5188   {
5189     Xalpha_h,                           TRUE,   FALSE,
5190     EL_CHAR('H'),                       -1, -1
5191   },
5192   {
5193     Xalpha_i,                           TRUE,   FALSE,
5194     EL_CHAR('I'),                       -1, -1
5195   },
5196   {
5197     Xalpha_j,                           TRUE,   FALSE,
5198     EL_CHAR('J'),                       -1, -1
5199   },
5200   {
5201     Xalpha_k,                           TRUE,   FALSE,
5202     EL_CHAR('K'),                       -1, -1
5203   },
5204   {
5205     Xalpha_l,                           TRUE,   FALSE,
5206     EL_CHAR('L'),                       -1, -1
5207   },
5208   {
5209     Xalpha_m,                           TRUE,   FALSE,
5210     EL_CHAR('M'),                       -1, -1
5211   },
5212   {
5213     Xalpha_n,                           TRUE,   FALSE,
5214     EL_CHAR('N'),                       -1, -1
5215   },
5216   {
5217     Xalpha_o,                           TRUE,   FALSE,
5218     EL_CHAR('O'),                       -1, -1
5219   },
5220   {
5221     Xalpha_p,                           TRUE,   FALSE,
5222     EL_CHAR('P'),                       -1, -1
5223   },
5224   {
5225     Xalpha_q,                           TRUE,   FALSE,
5226     EL_CHAR('Q'),                       -1, -1
5227   },
5228   {
5229     Xalpha_r,                           TRUE,   FALSE,
5230     EL_CHAR('R'),                       -1, -1
5231   },
5232   {
5233     Xalpha_s,                           TRUE,   FALSE,
5234     EL_CHAR('S'),                       -1, -1
5235   },
5236   {
5237     Xalpha_t,                           TRUE,   FALSE,
5238     EL_CHAR('T'),                       -1, -1
5239   },
5240   {
5241     Xalpha_u,                           TRUE,   FALSE,
5242     EL_CHAR('U'),                       -1, -1
5243   },
5244   {
5245     Xalpha_v,                           TRUE,   FALSE,
5246     EL_CHAR('V'),                       -1, -1
5247   },
5248   {
5249     Xalpha_w,                           TRUE,   FALSE,
5250     EL_CHAR('W'),                       -1, -1
5251   },
5252   {
5253     Xalpha_x,                           TRUE,   FALSE,
5254     EL_CHAR('X'),                       -1, -1
5255   },
5256   {
5257     Xalpha_y,                           TRUE,   FALSE,
5258     EL_CHAR('Y'),                       -1, -1
5259   },
5260   {
5261     Xalpha_z,                           TRUE,   FALSE,
5262     EL_CHAR('Z'),                       -1, -1
5263   },
5264   {
5265     Xalpha_arrow_e,                     TRUE,   FALSE,
5266     EL_CHAR('>'),                       -1, -1
5267   },
5268   {
5269     Xalpha_arrow_w,                     TRUE,   FALSE,
5270     EL_CHAR('<'),                       -1, -1
5271   },
5272   {
5273     Xalpha_copyr,                       TRUE,   FALSE,
5274     EL_CHAR('©'),                       -1, -1
5275   },
5276
5277   {
5278     Xboom_bug,                          FALSE,  FALSE,
5279     EL_BUG,                             ACTION_EXPLODING, -1
5280   },
5281   {
5282     Xboom_bomb,                         FALSE,  FALSE,
5283     EL_BOMB,                            ACTION_EXPLODING, -1
5284   },
5285   {
5286     Xboom_android,                      FALSE,  FALSE,
5287     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5288   },
5289   {
5290     Xboom_1,                            FALSE,  FALSE,
5291     EL_DEFAULT,                         ACTION_EXPLODING, -1
5292   },
5293   {
5294     Xboom_2,                            FALSE,  FALSE,
5295     EL_DEFAULT,                         ACTION_EXPLODING, -1
5296   },
5297   {
5298     Znormal,                            FALSE,  FALSE,
5299     EL_EMPTY,                           -1, -1
5300   },
5301   {
5302     Zdynamite,                          FALSE,  FALSE,
5303     EL_EMPTY,                           -1, -1
5304   },
5305   {
5306     Zplayer,                            FALSE,  FALSE,
5307     EL_EMPTY,                           -1, -1
5308   },
5309   {
5310     ZBORDER,                            FALSE,  FALSE,
5311     EL_EMPTY,                           -1, -1
5312   },
5313
5314   {
5315     -1,                                 FALSE,  FALSE,
5316     -1,                                 -1, -1
5317   }
5318 };
5319
5320 static struct Mapping_EM_to_RND_player
5321 {
5322   int action_em;
5323   int player_nr;
5324
5325   int element_rnd;
5326   int action;
5327   int direction;
5328 }
5329 em_player_mapping_list[] =
5330 {
5331   {
5332     SPR_walk + 0,                       0,
5333     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5334   },
5335   {
5336     SPR_walk + 1,                       0,
5337     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5338   },
5339   {
5340     SPR_walk + 2,                       0,
5341     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5342   },
5343   {
5344     SPR_walk + 3,                       0,
5345     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5346   },
5347   {
5348     SPR_push + 0,                       0,
5349     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5350   },
5351   {
5352     SPR_push + 1,                       0,
5353     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5354   },
5355   {
5356     SPR_push + 2,                       0,
5357     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5358   },
5359   {
5360     SPR_push + 3,                       0,
5361     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5362   },
5363   {
5364     SPR_spray + 0,                      0,
5365     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5366   },
5367   {
5368     SPR_spray + 1,                      0,
5369     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5370   },
5371   {
5372     SPR_spray + 2,                      0,
5373     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5374   },
5375   {
5376     SPR_spray + 3,                      0,
5377     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5378   },
5379   {
5380     SPR_walk + 0,                       1,
5381     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5382   },
5383   {
5384     SPR_walk + 1,                       1,
5385     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5386   },
5387   {
5388     SPR_walk + 2,                       1,
5389     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5390   },
5391   {
5392     SPR_walk + 3,                       1,
5393     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5394   },
5395   {
5396     SPR_push + 0,                       1,
5397     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5398   },
5399   {
5400     SPR_push + 1,                       1,
5401     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5402   },
5403   {
5404     SPR_push + 2,                       1,
5405     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5406   },
5407   {
5408     SPR_push + 3,                       1,
5409     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5410   },
5411   {
5412     SPR_spray + 0,                      1,
5413     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5414   },
5415   {
5416     SPR_spray + 1,                      1,
5417     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5418   },
5419   {
5420     SPR_spray + 2,                      1,
5421     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5422   },
5423   {
5424     SPR_spray + 3,                      1,
5425     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5426   },
5427   {
5428     SPR_still,                          0,
5429     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5430   },
5431   {
5432     SPR_still,                          1,
5433     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5434   },
5435   {
5436     SPR_walk + 0,                       2,
5437     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5438   },
5439   {
5440     SPR_walk + 1,                       2,
5441     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5442   },
5443   {
5444     SPR_walk + 2,                       2,
5445     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5446   },
5447   {
5448     SPR_walk + 3,                       2,
5449     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5450   },
5451   {
5452     SPR_push + 0,                       2,
5453     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5454   },
5455   {
5456     SPR_push + 1,                       2,
5457     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5458   },
5459   {
5460     SPR_push + 2,                       2,
5461     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5462   },
5463   {
5464     SPR_push + 3,                       2,
5465     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5466   },
5467   {
5468     SPR_spray + 0,                      2,
5469     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5470   },
5471   {
5472     SPR_spray + 1,                      2,
5473     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5474   },
5475   {
5476     SPR_spray + 2,                      2,
5477     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5478   },
5479   {
5480     SPR_spray + 3,                      2,
5481     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5482   },
5483   {
5484     SPR_walk + 0,                       3,
5485     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5486   },
5487   {
5488     SPR_walk + 1,                       3,
5489     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5490   },
5491   {
5492     SPR_walk + 2,                       3,
5493     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5494   },
5495   {
5496     SPR_walk + 3,                       3,
5497     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5498   },
5499   {
5500     SPR_push + 0,                       3,
5501     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5502   },
5503   {
5504     SPR_push + 1,                       3,
5505     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5506   },
5507   {
5508     SPR_push + 2,                       3,
5509     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5510   },
5511   {
5512     SPR_push + 3,                       3,
5513     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5514   },
5515   {
5516     SPR_spray + 0,                      3,
5517     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5518   },
5519   {
5520     SPR_spray + 1,                      3,
5521     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5522   },
5523   {
5524     SPR_spray + 2,                      3,
5525     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5526   },
5527   {
5528     SPR_spray + 3,                      3,
5529     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5530   },
5531   {
5532     SPR_still,                          2,
5533     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5534   },
5535   {
5536     SPR_still,                          3,
5537     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5538   },
5539
5540   {
5541     -1,                                 -1,
5542     -1,                                 -1, -1
5543   }
5544 };
5545
5546 int map_element_RND_to_EM(int element_rnd)
5547 {
5548   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5549   static boolean mapping_initialized = FALSE;
5550
5551   if (!mapping_initialized)
5552   {
5553     int i;
5554
5555     /* return "Xalpha_quest" for all undefined elements in mapping array */
5556     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5557       mapping_RND_to_EM[i] = Xalpha_quest;
5558
5559     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5560       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5561         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5562           em_object_mapping_list[i].element_em;
5563
5564     mapping_initialized = TRUE;
5565   }
5566
5567   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5568     return mapping_RND_to_EM[element_rnd];
5569
5570   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5571
5572   return EL_UNKNOWN;
5573 }
5574
5575 int map_element_EM_to_RND(int element_em)
5576 {
5577   static unsigned short mapping_EM_to_RND[TILE_MAX];
5578   static boolean mapping_initialized = FALSE;
5579
5580   if (!mapping_initialized)
5581   {
5582     int i;
5583
5584     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5585     for (i = 0; i < TILE_MAX; i++)
5586       mapping_EM_to_RND[i] = EL_UNKNOWN;
5587
5588     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5589       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5590         em_object_mapping_list[i].element_rnd;
5591
5592     mapping_initialized = TRUE;
5593   }
5594
5595   if (element_em >= 0 && element_em < TILE_MAX)
5596     return mapping_EM_to_RND[element_em];
5597
5598   Error(ERR_WARN, "invalid EM level element %d", element_em);
5599
5600   return EL_UNKNOWN;
5601 }
5602
5603 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5604 {
5605   struct LevelInfo_EM *level_em = level->native_em_level;
5606   struct LEVEL *lev = level_em->lev;
5607   int i, j;
5608
5609   for (i = 0; i < TILE_MAX; i++)
5610     lev->android_array[i] = Xblank;
5611
5612   for (i = 0; i < level->num_android_clone_elements; i++)
5613   {
5614     int element_rnd = level->android_clone_element[i];
5615     int element_em = map_element_RND_to_EM(element_rnd);
5616
5617     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5618       if (em_object_mapping_list[j].element_rnd == element_rnd)
5619         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5620   }
5621 }
5622
5623 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5624 {
5625   struct LevelInfo_EM *level_em = level->native_em_level;
5626   struct LEVEL *lev = level_em->lev;
5627   int i, j;
5628
5629   level->num_android_clone_elements = 0;
5630
5631   for (i = 0; i < TILE_MAX; i++)
5632   {
5633     int element_em = lev->android_array[i];
5634     int element_rnd;
5635     boolean element_found = FALSE;
5636
5637     if (element_em == Xblank)
5638       continue;
5639
5640     element_rnd = map_element_EM_to_RND(element_em);
5641
5642     for (j = 0; j < level->num_android_clone_elements; j++)
5643       if (level->android_clone_element[j] == element_rnd)
5644         element_found = TRUE;
5645
5646     if (!element_found)
5647     {
5648       level->android_clone_element[level->num_android_clone_elements++] =
5649         element_rnd;
5650
5651       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5652         break;
5653     }
5654   }
5655
5656   if (level->num_android_clone_elements == 0)
5657   {
5658     level->num_android_clone_elements = 1;
5659     level->android_clone_element[0] = EL_EMPTY;
5660   }
5661 }
5662
5663 int map_direction_RND_to_EM(int direction)
5664 {
5665   return (direction == MV_UP    ? 0 :
5666           direction == MV_RIGHT ? 1 :
5667           direction == MV_DOWN  ? 2 :
5668           direction == MV_LEFT  ? 3 :
5669           -1);
5670 }
5671
5672 int map_direction_EM_to_RND(int direction)
5673 {
5674   return (direction == 0 ? MV_UP    :
5675           direction == 1 ? MV_RIGHT :
5676           direction == 2 ? MV_DOWN  :
5677           direction == 3 ? MV_LEFT  :
5678           MV_NONE);
5679 }
5680
5681 int get_next_element(int element)
5682 {
5683   switch (element)
5684   {
5685     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5686     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5687     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5688     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5689     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5690     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5691     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5692     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5693     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5694     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5695     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5696
5697     default:                            return element;
5698   }
5699 }
5700
5701 #if 0
5702 int el_act_dir2img(int element, int action, int direction)
5703 {
5704   element = GFX_ELEMENT(element);
5705
5706   if (direction == MV_NONE)
5707     return element_info[element].graphic[action];
5708
5709   direction = MV_DIR_TO_BIT(direction);
5710
5711   return element_info[element].direction_graphic[action][direction];
5712 }
5713 #else
5714 int el_act_dir2img(int element, int action, int direction)
5715 {
5716   element = GFX_ELEMENT(element);
5717   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5718
5719   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5720   return element_info[element].direction_graphic[action][direction];
5721 }
5722 #endif
5723
5724 #if 0
5725 static int el_act_dir2crm(int element, int action, int direction)
5726 {
5727   element = GFX_ELEMENT(element);
5728
5729   if (direction == MV_NONE)
5730     return element_info[element].crumbled[action];
5731
5732   direction = MV_DIR_TO_BIT(direction);
5733
5734   return element_info[element].direction_crumbled[action][direction];
5735 }
5736 #else
5737 static int el_act_dir2crm(int element, int action, int direction)
5738 {
5739   element = GFX_ELEMENT(element);
5740   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5741
5742   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5743   return element_info[element].direction_crumbled[action][direction];
5744 }
5745 #endif
5746
5747 int el_act2img(int element, int action)
5748 {
5749   element = GFX_ELEMENT(element);
5750
5751   return element_info[element].graphic[action];
5752 }
5753
5754 int el_act2crm(int element, int action)
5755 {
5756   element = GFX_ELEMENT(element);
5757
5758   return element_info[element].crumbled[action];
5759 }
5760
5761 int el_dir2img(int element, int direction)
5762 {
5763   element = GFX_ELEMENT(element);
5764
5765   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5766 }
5767
5768 int el2baseimg(int element)
5769 {
5770   return element_info[element].graphic[ACTION_DEFAULT];
5771 }
5772
5773 int el2img(int element)
5774 {
5775   element = GFX_ELEMENT(element);
5776
5777   return element_info[element].graphic[ACTION_DEFAULT];
5778 }
5779
5780 int el2edimg(int element)
5781 {
5782   element = GFX_ELEMENT(element);
5783
5784   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5785 }
5786
5787 int el2preimg(int element)
5788 {
5789   element = GFX_ELEMENT(element);
5790
5791   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5792 }
5793
5794 int el2panelimg(int element)
5795 {
5796   element = GFX_ELEMENT(element);
5797
5798   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5799 }
5800
5801 int font2baseimg(int font_nr)
5802 {
5803   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5804 }
5805
5806 int getBeltNrFromBeltElement(int element)
5807 {
5808   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5809           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5810           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5811 }
5812
5813 int getBeltNrFromBeltActiveElement(int element)
5814 {
5815   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5816           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5817           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5818 }
5819
5820 int getBeltNrFromBeltSwitchElement(int element)
5821 {
5822   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5823           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5824           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5825 }
5826
5827 int getBeltDirNrFromBeltElement(int element)
5828 {
5829   static int belt_base_element[4] =
5830   {
5831     EL_CONVEYOR_BELT_1_LEFT,
5832     EL_CONVEYOR_BELT_2_LEFT,
5833     EL_CONVEYOR_BELT_3_LEFT,
5834     EL_CONVEYOR_BELT_4_LEFT
5835   };
5836
5837   int belt_nr = getBeltNrFromBeltElement(element);
5838   int belt_dir_nr = element - belt_base_element[belt_nr];
5839
5840   return (belt_dir_nr % 3);
5841 }
5842
5843 int getBeltDirNrFromBeltSwitchElement(int element)
5844 {
5845   static int belt_base_element[4] =
5846   {
5847     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5848     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5849     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5850     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5851   };
5852
5853   int belt_nr = getBeltNrFromBeltSwitchElement(element);
5854   int belt_dir_nr = element - belt_base_element[belt_nr];
5855
5856   return (belt_dir_nr % 3);
5857 }
5858
5859 int getBeltDirFromBeltElement(int element)
5860 {
5861   static int belt_move_dir[3] =
5862   {
5863     MV_LEFT,
5864     MV_NONE,
5865     MV_RIGHT
5866   };
5867
5868   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5869
5870   return belt_move_dir[belt_dir_nr];
5871 }
5872
5873 int getBeltDirFromBeltSwitchElement(int element)
5874 {
5875   static int belt_move_dir[3] =
5876   {
5877     MV_LEFT,
5878     MV_NONE,
5879     MV_RIGHT
5880   };
5881
5882   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5883
5884   return belt_move_dir[belt_dir_nr];
5885 }
5886
5887 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5888 {
5889   static int belt_base_element[4] =
5890   {
5891     EL_CONVEYOR_BELT_1_LEFT,
5892     EL_CONVEYOR_BELT_2_LEFT,
5893     EL_CONVEYOR_BELT_3_LEFT,
5894     EL_CONVEYOR_BELT_4_LEFT
5895   };
5896
5897   return belt_base_element[belt_nr] + belt_dir_nr;
5898 }
5899
5900 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5901 {
5902   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5903
5904   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5905 }
5906
5907 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5908 {
5909   static int belt_base_element[4] =
5910   {
5911     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5912     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5913     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5914     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5915   };
5916
5917   return belt_base_element[belt_nr] + belt_dir_nr;
5918 }
5919
5920 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5921 {
5922   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5923
5924   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5925 }
5926
5927 int getNumActivePlayers_EM()
5928 {
5929   int num_players = 0;
5930   int i;
5931
5932   if (!tape.playing)
5933     return -1;
5934
5935   for (i = 0; i < MAX_PLAYERS; i++)
5936     if (tape.player_participates[i])
5937       num_players++;
5938
5939   return num_players;
5940 }
5941
5942 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5943 {
5944   int game_frame_delay_value;
5945
5946   game_frame_delay_value =
5947     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5948      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5949      GameFrameDelay);
5950
5951   if (tape.playing && tape.warp_forward && !tape.pausing)
5952     game_frame_delay_value = 0;
5953
5954   return game_frame_delay_value;
5955 }
5956
5957 unsigned int InitRND(long seed)
5958 {
5959   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5960     return InitEngineRandom_EM(seed);
5961   else
5962     return InitEngineRandom_RND(seed);
5963 }
5964
5965 #if 1
5966 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5967 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5968 #endif
5969
5970 void ResetGfxAnimation_EM(int x, int y, int tile)
5971 {
5972   GfxFrame[x][y] = 0;
5973 }
5974
5975 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5976                                   Bitmap **src_bitmap, int *src_x, int *src_y,
5977                                   int x, int y)
5978 {
5979   int element         = object_mapping[tile].element_rnd;
5980   int action          = object_mapping[tile].action;
5981   int direction       = object_mapping[tile].direction;
5982   boolean is_backside = object_mapping[tile].is_backside;
5983   boolean action_removing = (action == ACTION_DIGGING ||
5984                              action == ACTION_SNAPPING ||
5985                              action == ACTION_COLLECTING);
5986   int effective_element = (frame_em > 0 ? element :
5987                            is_backside ? EL_EMPTY :
5988                            action_removing ? EL_EMPTY :
5989                            element);
5990   int graphic = (direction == MV_NONE ?
5991                  el_act2img(effective_element, action) :
5992                  el_act_dir2img(effective_element, action, direction));
5993   struct GraphicInfo *g = &graphic_info[graphic];
5994   int sync_frame;
5995
5996   if (graphic_info[graphic].anim_global_sync)
5997     sync_frame = FrameCounter;
5998   else
5999     sync_frame = 7 - frame_em;
6000
6001   SetRandomAnimationValue(x, y);
6002
6003   int frame = getAnimationFrame(g->anim_frames,
6004                                 g->anim_delay,
6005                                 g->anim_mode,
6006                                 g->anim_start_frame,
6007                                 sync_frame);
6008
6009   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6010 }
6011
6012 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
6013                                   Bitmap **src_bitmap, int *src_x, int *src_y)
6014 {
6015   int element   = player_mapping[player_nr][anim].element_rnd;
6016   int action    = player_mapping[player_nr][anim].action;
6017   int direction = player_mapping[player_nr][anim].direction;
6018   int graphic = (direction == MV_NONE ?
6019                  el_act2img(element, action) :
6020                  el_act_dir2img(element, action, direction));
6021   struct GraphicInfo *g = &graphic_info[graphic];
6022   int sync_frame;
6023
6024   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6025
6026   stored_player[player_nr].StepFrame = 7 - frame_em;
6027
6028   sync_frame = stored_player[player_nr].Frame;
6029
6030 #if 0
6031   printf("::: %d: %d, %d [%d]\n",
6032          player_nr,
6033          stored_player[player_nr].Frame,
6034          stored_player[player_nr].StepFrame,
6035          FrameCounter);
6036 #endif
6037
6038   int frame = getAnimationFrame(g->anim_frames,
6039                                 g->anim_delay,
6040                                 g->anim_mode,
6041                                 g->anim_start_frame,
6042                                 sync_frame);
6043
6044   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
6045 }
6046
6047 void InitGraphicInfo_EM(void)
6048 {
6049 #if 0
6050   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6051   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6052 #endif
6053   int i, j, p;
6054
6055 #if DEBUG_EM_GFX
6056   int num_em_gfx_errors = 0;
6057
6058   if (graphic_info_em_object[0][0].bitmap == NULL)
6059   {
6060     /* EM graphics not yet initialized in em_open_all() */
6061
6062     return;
6063   }
6064
6065   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6066 #endif
6067
6068   /* always start with reliable default values */
6069   for (i = 0; i < TILE_MAX; i++)
6070   {
6071     object_mapping[i].element_rnd = EL_UNKNOWN;
6072     object_mapping[i].is_backside = FALSE;
6073     object_mapping[i].action = ACTION_DEFAULT;
6074     object_mapping[i].direction = MV_NONE;
6075   }
6076
6077   /* always start with reliable default values */
6078   for (p = 0; p < MAX_PLAYERS; p++)
6079   {
6080     for (i = 0; i < SPR_MAX; i++)
6081     {
6082       player_mapping[p][i].element_rnd = EL_UNKNOWN;
6083       player_mapping[p][i].action = ACTION_DEFAULT;
6084       player_mapping[p][i].direction = MV_NONE;
6085     }
6086   }
6087
6088   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6089   {
6090     int e = em_object_mapping_list[i].element_em;
6091
6092     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6093     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6094
6095     if (em_object_mapping_list[i].action != -1)
6096       object_mapping[e].action = em_object_mapping_list[i].action;
6097
6098     if (em_object_mapping_list[i].direction != -1)
6099       object_mapping[e].direction =
6100         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6101   }
6102
6103   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6104   {
6105     int a = em_player_mapping_list[i].action_em;
6106     int p = em_player_mapping_list[i].player_nr;
6107
6108     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6109
6110     if (em_player_mapping_list[i].action != -1)
6111       player_mapping[p][a].action = em_player_mapping_list[i].action;
6112
6113     if (em_player_mapping_list[i].direction != -1)
6114       player_mapping[p][a].direction =
6115         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6116   }
6117
6118   for (i = 0; i < TILE_MAX; i++)
6119   {
6120     int element = object_mapping[i].element_rnd;
6121     int action = object_mapping[i].action;
6122     int direction = object_mapping[i].direction;
6123     boolean is_backside = object_mapping[i].is_backside;
6124     boolean action_removing = (action == ACTION_DIGGING ||
6125                                action == ACTION_SNAPPING ||
6126                                action == ACTION_COLLECTING);
6127     boolean action_exploding = ((action == ACTION_EXPLODING ||
6128                                  action == ACTION_SMASHED_BY_ROCK ||
6129                                  action == ACTION_SMASHED_BY_SPRING) &&
6130                                 element != EL_DIAMOND);
6131     boolean action_active = (action == ACTION_ACTIVE);
6132     boolean action_other = (action == ACTION_OTHER);
6133
6134     for (j = 0; j < 8; j++)
6135     {
6136       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6137                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6138                                j < 7 ? element :
6139                                i == Xdrip_stretch ? element :
6140                                i == Xdrip_stretchB ? element :
6141                                i == Ydrip_s1 ? element :
6142                                i == Ydrip_s1B ? element :
6143                                i == Xball_1B ? element :
6144                                i == Xball_2 ? element :
6145                                i == Xball_2B ? element :
6146                                i == Yball_eat ? element :
6147                                i == Ykey_1_eat ? element :
6148                                i == Ykey_2_eat ? element :
6149                                i == Ykey_3_eat ? element :
6150                                i == Ykey_4_eat ? element :
6151                                i == Ykey_5_eat ? element :
6152                                i == Ykey_6_eat ? element :
6153                                i == Ykey_7_eat ? element :
6154                                i == Ykey_8_eat ? element :
6155                                i == Ylenses_eat ? element :
6156                                i == Ymagnify_eat ? element :
6157                                i == Ygrass_eat ? element :
6158                                i == Ydirt_eat ? element :
6159                                i == Yemerald_stone ? EL_EMERALD :
6160                                i == Ydiamond_stone ? EL_ROCK :
6161                                i == Xsand_stonein_1 ? element :
6162                                i == Xsand_stonein_2 ? element :
6163                                i == Xsand_stonein_3 ? element :
6164                                i == Xsand_stonein_4 ? element :
6165                                is_backside ? EL_EMPTY :
6166                                action_removing ? EL_EMPTY :
6167                                element);
6168       int effective_action = (j < 7 ? action :
6169                               i == Xdrip_stretch ? action :
6170                               i == Xdrip_stretchB ? action :
6171                               i == Ydrip_s1 ? action :
6172                               i == Ydrip_s1B ? action :
6173                               i == Xball_1B ? action :
6174                               i == Xball_2 ? action :
6175                               i == Xball_2B ? action :
6176                               i == Yball_eat ? action :
6177                               i == Ykey_1_eat ? action :
6178                               i == Ykey_2_eat ? action :
6179                               i == Ykey_3_eat ? action :
6180                               i == Ykey_4_eat ? action :
6181                               i == Ykey_5_eat ? action :
6182                               i == Ykey_6_eat ? action :
6183                               i == Ykey_7_eat ? action :
6184                               i == Ykey_8_eat ? action :
6185                               i == Ylenses_eat ? action :
6186                               i == Ymagnify_eat ? action :
6187                               i == Ygrass_eat ? action :
6188                               i == Ydirt_eat ? action :
6189                               i == Xsand_stonein_1 ? action :
6190                               i == Xsand_stonein_2 ? action :
6191                               i == Xsand_stonein_3 ? action :
6192                               i == Xsand_stonein_4 ? action :
6193                               i == Xsand_stoneout_1 ? action :
6194                               i == Xsand_stoneout_2 ? action :
6195                               i == Xboom_android ? ACTION_EXPLODING :
6196                               action_exploding ? ACTION_EXPLODING :
6197                               action_active ? action :
6198                               action_other ? action :
6199                               ACTION_DEFAULT);
6200       int graphic = (el_act_dir2img(effective_element, effective_action,
6201                                     direction));
6202       int crumbled = (el_act_dir2crm(effective_element, effective_action,
6203                                      direction));
6204       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6205       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6206       boolean has_action_graphics = (graphic != base_graphic);
6207       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6208       struct GraphicInfo *g = &graphic_info[graphic];
6209       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6210       Bitmap *src_bitmap;
6211       int src_x, src_y;
6212       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6213       boolean special_animation = (action != ACTION_DEFAULT &&
6214                                    g->anim_frames == 3 &&
6215                                    g->anim_delay == 2 &&
6216                                    g->anim_mode & ANIM_LINEAR);
6217       int sync_frame = (i == Xdrip_stretch ? 7 :
6218                         i == Xdrip_stretchB ? 7 :
6219                         i == Ydrip_s2 ? j + 8 :
6220                         i == Ydrip_s2B ? j + 8 :
6221                         i == Xacid_1 ? 0 :
6222                         i == Xacid_2 ? 10 :
6223                         i == Xacid_3 ? 20 :
6224                         i == Xacid_4 ? 30 :
6225                         i == Xacid_5 ? 40 :
6226                         i == Xacid_6 ? 50 :
6227                         i == Xacid_7 ? 60 :
6228                         i == Xacid_8 ? 70 :
6229                         i == Xfake_acid_1 ? 0 :
6230                         i == Xfake_acid_2 ? 10 :
6231                         i == Xfake_acid_3 ? 20 :
6232                         i == Xfake_acid_4 ? 30 :
6233                         i == Xfake_acid_5 ? 40 :
6234                         i == Xfake_acid_6 ? 50 :
6235                         i == Xfake_acid_7 ? 60 :
6236                         i == Xfake_acid_8 ? 70 :
6237                         i == Xball_2 ? 7 :
6238                         i == Xball_2B ? j + 8 :
6239                         i == Yball_eat ? j + 1 :
6240                         i == Ykey_1_eat ? j + 1 :
6241                         i == Ykey_2_eat ? j + 1 :
6242                         i == Ykey_3_eat ? j + 1 :
6243                         i == Ykey_4_eat ? j + 1 :
6244                         i == Ykey_5_eat ? j + 1 :
6245                         i == Ykey_6_eat ? j + 1 :
6246                         i == Ykey_7_eat ? j + 1 :
6247                         i == Ykey_8_eat ? j + 1 :
6248                         i == Ylenses_eat ? j + 1 :
6249                         i == Ymagnify_eat ? j + 1 :
6250                         i == Ygrass_eat ? j + 1 :
6251                         i == Ydirt_eat ? j + 1 :
6252                         i == Xamoeba_1 ? 0 :
6253                         i == Xamoeba_2 ? 1 :
6254                         i == Xamoeba_3 ? 2 :
6255                         i == Xamoeba_4 ? 3 :
6256                         i == Xamoeba_5 ? 0 :
6257                         i == Xamoeba_6 ? 1 :
6258                         i == Xamoeba_7 ? 2 :
6259                         i == Xamoeba_8 ? 3 :
6260                         i == Xexit_2 ? j + 8 :
6261                         i == Xexit_3 ? j + 16 :
6262                         i == Xdynamite_1 ? 0 :
6263                         i == Xdynamite_2 ? 8 :
6264                         i == Xdynamite_3 ? 16 :
6265                         i == Xdynamite_4 ? 24 :
6266                         i == Xsand_stonein_1 ? j + 1 :
6267                         i == Xsand_stonein_2 ? j + 9 :
6268                         i == Xsand_stonein_3 ? j + 17 :
6269                         i == Xsand_stonein_4 ? j + 25 :
6270                         i == Xsand_stoneout_1 && j == 0 ? 0 :
6271                         i == Xsand_stoneout_1 && j == 1 ? 0 :
6272                         i == Xsand_stoneout_1 && j == 2 ? 1 :
6273                         i == Xsand_stoneout_1 && j == 3 ? 2 :
6274                         i == Xsand_stoneout_1 && j == 4 ? 2 :
6275                         i == Xsand_stoneout_1 && j == 5 ? 3 :
6276                         i == Xsand_stoneout_1 && j == 6 ? 4 :
6277                         i == Xsand_stoneout_1 && j == 7 ? 4 :
6278                         i == Xsand_stoneout_2 && j == 0 ? 5 :
6279                         i == Xsand_stoneout_2 && j == 1 ? 6 :
6280                         i == Xsand_stoneout_2 && j == 2 ? 7 :
6281                         i == Xsand_stoneout_2 && j == 3 ? 8 :
6282                         i == Xsand_stoneout_2 && j == 4 ? 9 :
6283                         i == Xsand_stoneout_2 && j == 5 ? 11 :
6284                         i == Xsand_stoneout_2 && j == 6 ? 13 :
6285                         i == Xsand_stoneout_2 && j == 7 ? 15 :
6286                         i == Xboom_bug && j == 1 ? 2 :
6287                         i == Xboom_bug && j == 2 ? 2 :
6288                         i == Xboom_bug && j == 3 ? 4 :
6289                         i == Xboom_bug && j == 4 ? 4 :
6290                         i == Xboom_bug && j == 5 ? 2 :
6291                         i == Xboom_bug && j == 6 ? 2 :
6292                         i == Xboom_bug && j == 7 ? 0 :
6293                         i == Xboom_bomb && j == 1 ? 2 :
6294                         i == Xboom_bomb && j == 2 ? 2 :
6295                         i == Xboom_bomb && j == 3 ? 4 :
6296                         i == Xboom_bomb && j == 4 ? 4 :
6297                         i == Xboom_bomb && j == 5 ? 2 :
6298                         i == Xboom_bomb && j == 6 ? 2 :
6299                         i == Xboom_bomb && j == 7 ? 0 :
6300                         i == Xboom_android && j == 7 ? 6 :
6301                         i == Xboom_1 && j == 1 ? 2 :
6302                         i == Xboom_1 && j == 2 ? 2 :
6303                         i == Xboom_1 && j == 3 ? 4 :
6304                         i == Xboom_1 && j == 4 ? 4 :
6305                         i == Xboom_1 && j == 5 ? 6 :
6306                         i == Xboom_1 && j == 6 ? 6 :
6307                         i == Xboom_1 && j == 7 ? 8 :
6308                         i == Xboom_2 && j == 0 ? 8 :
6309                         i == Xboom_2 && j == 1 ? 8 :
6310                         i == Xboom_2 && j == 2 ? 10 :
6311                         i == Xboom_2 && j == 3 ? 10 :
6312                         i == Xboom_2 && j == 4 ? 10 :
6313                         i == Xboom_2 && j == 5 ? 12 :
6314                         i == Xboom_2 && j == 6 ? 12 :
6315                         i == Xboom_2 && j == 7 ? 12 :
6316                         special_animation && j == 4 ? 3 :
6317                         effective_action != action ? 0 :
6318                         j);
6319
6320 #if DEBUG_EM_GFX
6321       Bitmap *debug_bitmap = g_em->bitmap;
6322       int debug_src_x = g_em->src_x;
6323       int debug_src_y = g_em->src_y;
6324 #endif
6325
6326       int frame = getAnimationFrame(g->anim_frames,
6327                                     g->anim_delay,
6328                                     g->anim_mode,
6329                                     g->anim_start_frame,
6330                                     sync_frame);
6331
6332       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6333                           g->double_movement && is_backside);
6334
6335       g_em->bitmap = src_bitmap;
6336       g_em->src_x = src_x;
6337       g_em->src_y = src_y;
6338       g_em->src_offset_x = 0;
6339       g_em->src_offset_y = 0;
6340       g_em->dst_offset_x = 0;
6341       g_em->dst_offset_y = 0;
6342       g_em->width  = TILEX;
6343       g_em->height = TILEY;
6344
6345       g_em->crumbled_bitmap = NULL;
6346       g_em->crumbled_src_x = 0;
6347       g_em->crumbled_src_y = 0;
6348       g_em->crumbled_border_size = 0;
6349
6350       g_em->has_crumbled_graphics = FALSE;
6351       g_em->preserve_background = FALSE;
6352
6353 #if 0
6354       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6355         printf("::: empty crumbled: %d [%s], %d, %d\n",
6356                effective_element, element_info[effective_element].token_name,
6357                effective_action, direction);
6358 #endif
6359
6360       /* if element can be crumbled, but certain action graphics are just empty
6361          space (like snapping sand with the original R'n'D graphics), do not
6362          treat these empty space graphics as crumbled graphics in EMC engine */
6363       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6364       {
6365         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6366
6367         g_em->has_crumbled_graphics = TRUE;
6368         g_em->crumbled_bitmap = src_bitmap;
6369         g_em->crumbled_src_x = src_x;
6370         g_em->crumbled_src_y = src_y;
6371         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6372       }
6373
6374 #if 0
6375       if (element == EL_ROCK &&
6376           effective_action == ACTION_FILLING)
6377         printf("::: has_action_graphics == %d\n", has_action_graphics);
6378 #endif
6379
6380       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6381                                    effective_action == ACTION_MOVING  ||
6382                                    effective_action == ACTION_PUSHING ||
6383                                    effective_action == ACTION_EATING)) ||
6384           (!has_action_graphics && (effective_action == ACTION_FILLING ||
6385                                     effective_action == ACTION_EMPTYING)))
6386       {
6387         int move_dir =
6388           (effective_action == ACTION_FALLING ||
6389            effective_action == ACTION_FILLING ||
6390            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6391         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6392         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
6393         int num_steps = (i == Ydrip_s1  ? 16 :
6394                          i == Ydrip_s1B ? 16 :
6395                          i == Ydrip_s2  ? 16 :
6396                          i == Ydrip_s2B ? 16 :
6397                          i == Xsand_stonein_1 ? 32 :
6398                          i == Xsand_stonein_2 ? 32 :
6399                          i == Xsand_stonein_3 ? 32 :
6400                          i == Xsand_stonein_4 ? 32 :
6401                          i == Xsand_stoneout_1 ? 16 :
6402                          i == Xsand_stoneout_2 ? 16 : 8);
6403         int cx = ABS(dx) * (TILEX / num_steps);
6404         int cy = ABS(dy) * (TILEY / num_steps);
6405         int step_frame = (i == Ydrip_s2         ? j + 8 :
6406                           i == Ydrip_s2B        ? j + 8 :
6407                           i == Xsand_stonein_2  ? j + 8 :
6408                           i == Xsand_stonein_3  ? j + 16 :
6409                           i == Xsand_stonein_4  ? j + 24 :
6410                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6411         int step = (is_backside ? step_frame : num_steps - step_frame);
6412
6413         if (is_backside)        /* tile where movement starts */
6414         {
6415           if (dx < 0 || dy < 0)
6416           {
6417             g_em->src_offset_x = cx * step;
6418             g_em->src_offset_y = cy * step;
6419           }
6420           else
6421           {
6422             g_em->dst_offset_x = cx * step;
6423             g_em->dst_offset_y = cy * step;
6424           }
6425         }
6426         else                    /* tile where movement ends */
6427         {
6428           if (dx < 0 || dy < 0)
6429           {
6430             g_em->dst_offset_x = cx * step;
6431             g_em->dst_offset_y = cy * step;
6432           }
6433           else
6434           {
6435             g_em->src_offset_x = cx * step;
6436             g_em->src_offset_y = cy * step;
6437           }
6438         }
6439
6440         g_em->width  = TILEX - cx * step;
6441         g_em->height = TILEY - cy * step;
6442       }
6443
6444       /* create unique graphic identifier to decide if tile must be redrawn */
6445       /* bit 31 - 16 (16 bit): EM style graphic
6446          bit 15 - 12 ( 4 bit): EM style frame
6447          bit 11 -  6 ( 6 bit): graphic width
6448          bit  5 -  0 ( 6 bit): graphic height */
6449       g_em->unique_identifier =
6450         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6451
6452 #if DEBUG_EM_GFX
6453
6454       /* skip check for EMC elements not contained in original EMC artwork */
6455       if (element == EL_EMC_FAKE_ACID)
6456         continue;
6457
6458       if (g_em->bitmap != debug_bitmap ||
6459           g_em->src_x != debug_src_x ||
6460           g_em->src_y != debug_src_y ||
6461           g_em->src_offset_x != 0 ||
6462           g_em->src_offset_y != 0 ||
6463           g_em->dst_offset_x != 0 ||
6464           g_em->dst_offset_y != 0 ||
6465           g_em->width != TILEX ||
6466           g_em->height != TILEY)
6467       {
6468         static int last_i = -1;
6469
6470         if (i != last_i)
6471         {
6472           printf("\n");
6473           last_i = i;
6474         }
6475
6476         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6477                i, element, element_info[element].token_name,
6478                element_action_info[effective_action].suffix, direction);
6479
6480         if (element != effective_element)
6481           printf(" [%d ('%s')]",
6482                  effective_element,
6483                  element_info[effective_element].token_name);
6484
6485         printf("\n");
6486
6487         if (g_em->bitmap != debug_bitmap)
6488           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6489                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6490
6491         if (g_em->src_x != debug_src_x ||
6492             g_em->src_y != debug_src_y)
6493           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6494                  j, (is_backside ? 'B' : 'F'),
6495                  g_em->src_x, g_em->src_y,
6496                  g_em->src_x / 32, g_em->src_y / 32,
6497                  debug_src_x, debug_src_y,
6498                  debug_src_x / 32, debug_src_y / 32);
6499
6500         if (g_em->src_offset_x != 0 ||
6501             g_em->src_offset_y != 0 ||
6502             g_em->dst_offset_x != 0 ||
6503             g_em->dst_offset_y != 0)
6504           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6505                  j, is_backside,
6506                  g_em->src_offset_x, g_em->src_offset_y,
6507                  g_em->dst_offset_x, g_em->dst_offset_y);
6508
6509         if (g_em->width != TILEX ||
6510             g_em->height != TILEY)
6511           printf("    %d (%d): size %d,%d should be %d,%d\n",
6512                  j, is_backside,
6513                  g_em->width, g_em->height, TILEX, TILEY);
6514
6515         num_em_gfx_errors++;
6516       }
6517 #endif
6518
6519     }
6520   }
6521
6522   for (i = 0; i < TILE_MAX; i++)
6523   {
6524     for (j = 0; j < 8; j++)
6525     {
6526       int element = object_mapping[i].element_rnd;
6527       int action = object_mapping[i].action;
6528       int direction = object_mapping[i].direction;
6529       boolean is_backside = object_mapping[i].is_backside;
6530       int graphic_action  = el_act_dir2img(element, action, direction);
6531       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6532
6533       if ((action == ACTION_SMASHED_BY_ROCK ||
6534            action == ACTION_SMASHED_BY_SPRING ||
6535            action == ACTION_EATING) &&
6536           graphic_action == graphic_default)
6537       {
6538         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6539                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6540                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6541                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6542                  Xspring);
6543
6544         /* no separate animation for "smashed by rock" -- use rock instead */
6545         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6546         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6547
6548         g_em->bitmap            = g_xx->bitmap;
6549         g_em->src_x             = g_xx->src_x;
6550         g_em->src_y             = g_xx->src_y;
6551         g_em->src_offset_x      = g_xx->src_offset_x;
6552         g_em->src_offset_y      = g_xx->src_offset_y;
6553         g_em->dst_offset_x      = g_xx->dst_offset_x;
6554         g_em->dst_offset_y      = g_xx->dst_offset_y;
6555         g_em->width             = g_xx->width;
6556         g_em->height            = g_xx->height;
6557         g_em->unique_identifier = g_xx->unique_identifier;
6558
6559         if (!is_backside)
6560           g_em->preserve_background = TRUE;
6561       }
6562     }
6563   }
6564
6565   for (p = 0; p < MAX_PLAYERS; p++)
6566   {
6567     for (i = 0; i < SPR_MAX; i++)
6568     {
6569       int element = player_mapping[p][i].element_rnd;
6570       int action = player_mapping[p][i].action;
6571       int direction = player_mapping[p][i].direction;
6572
6573       for (j = 0; j < 8; j++)
6574       {
6575         int effective_element = element;
6576         int effective_action = action;
6577         int graphic = (direction == MV_NONE ?
6578                        el_act2img(effective_element, effective_action) :
6579                        el_act_dir2img(effective_element, effective_action,
6580                                       direction));
6581         struct GraphicInfo *g = &graphic_info[graphic];
6582         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6583         Bitmap *src_bitmap;
6584         int src_x, src_y;
6585         int sync_frame = j;
6586
6587 #if DEBUG_EM_GFX
6588         Bitmap *debug_bitmap = g_em->bitmap;
6589         int debug_src_x = g_em->src_x;
6590         int debug_src_y = g_em->src_y;
6591 #endif
6592
6593         int frame = getAnimationFrame(g->anim_frames,
6594                                       g->anim_delay,
6595                                       g->anim_mode,
6596                                       g->anim_start_frame,
6597                                       sync_frame);
6598
6599         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6600
6601         g_em->bitmap = src_bitmap;
6602         g_em->src_x = src_x;
6603         g_em->src_y = src_y;
6604         g_em->src_offset_x = 0;
6605         g_em->src_offset_y = 0;
6606         g_em->dst_offset_x = 0;
6607         g_em->dst_offset_y = 0;
6608         g_em->width  = TILEX;
6609         g_em->height = TILEY;
6610
6611 #if DEBUG_EM_GFX
6612
6613         /* skip check for EMC elements not contained in original EMC artwork */
6614         if (element == EL_PLAYER_3 ||
6615             element == EL_PLAYER_4)
6616           continue;
6617
6618         if (g_em->bitmap != debug_bitmap ||
6619             g_em->src_x != debug_src_x ||
6620             g_em->src_y != debug_src_y)
6621         {
6622           static int last_i = -1;
6623
6624           if (i != last_i)
6625           {
6626             printf("\n");
6627             last_i = i;
6628           }
6629
6630           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6631                  p, i, element, element_info[element].token_name,
6632                  element_action_info[effective_action].suffix, direction);
6633
6634           if (element != effective_element)
6635             printf(" [%d ('%s')]",
6636                    effective_element,
6637                    element_info[effective_element].token_name);
6638
6639           printf("\n");
6640
6641           if (g_em->bitmap != debug_bitmap)
6642             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6643                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6644
6645           if (g_em->src_x != debug_src_x ||
6646               g_em->src_y != debug_src_y)
6647             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6648                    j,
6649                    g_em->src_x, g_em->src_y,
6650                    g_em->src_x / 32, g_em->src_y / 32,
6651                    debug_src_x, debug_src_y,
6652                    debug_src_x / 32, debug_src_y / 32);
6653
6654           num_em_gfx_errors++;
6655         }
6656 #endif
6657
6658       }
6659     }
6660   }
6661
6662 #if DEBUG_EM_GFX
6663   printf("\n");
6664   printf("::: [%d errors found]\n", num_em_gfx_errors);
6665
6666   exit(0);
6667 #endif
6668 }
6669
6670 void PlayMenuSoundExt(int sound)
6671 {
6672   if (sound == SND_UNDEFINED)
6673     return;
6674
6675   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6676       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6677     return;
6678
6679   if (IS_LOOP_SOUND(sound))
6680     PlaySoundLoop(sound);
6681   else
6682     PlaySound(sound);
6683 }
6684
6685 void PlayMenuSound()
6686 {
6687   PlayMenuSoundExt(menu.sound[game_status]);
6688 }
6689
6690 void PlayMenuSoundStereo(int sound, int stereo_position)
6691 {
6692   if (sound == SND_UNDEFINED)
6693     return;
6694
6695   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6696       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6697     return;
6698
6699   if (IS_LOOP_SOUND(sound))
6700     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6701   else
6702     PlaySoundStereo(sound, stereo_position);
6703 }
6704
6705 void PlayMenuSoundIfLoopExt(int sound)
6706 {
6707   if (sound == SND_UNDEFINED)
6708     return;
6709
6710   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6711       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6712     return;
6713
6714   if (IS_LOOP_SOUND(sound))
6715     PlaySoundLoop(sound);
6716 }
6717
6718 void PlayMenuSoundIfLoop()
6719 {
6720   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6721 }
6722
6723 void PlayMenuMusicExt(int music)
6724 {
6725   if (music == MUS_UNDEFINED)
6726     return;
6727
6728   if (!setup.sound_music)
6729     return;
6730
6731   PlayMusic(music);
6732 }
6733
6734 void PlayMenuMusic()
6735 {
6736   PlayMenuMusicExt(menu.music[game_status]);
6737 }
6738
6739 void PlaySoundActivating()
6740 {
6741 #if 0
6742   PlaySound(SND_MENU_ITEM_ACTIVATING);
6743 #endif
6744 }
6745
6746 void PlaySoundSelecting()
6747 {
6748 #if 0
6749   PlaySound(SND_MENU_ITEM_SELECTING);
6750 #endif
6751 }
6752
6753 void ToggleFullscreenIfNeeded()
6754 {
6755   boolean change_fullscreen = (setup.fullscreen !=
6756                                video.fullscreen_enabled);
6757   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6758                                     !strEqual(setup.fullscreen_mode,
6759                                               video.fullscreen_mode_current));
6760
6761   if (!video.fullscreen_available)
6762     return;
6763
6764 #if 1
6765   if (change_fullscreen || change_fullscreen_mode)
6766 #else
6767   if (setup.fullscreen != video.fullscreen_enabled ||
6768       setup.fullscreen_mode != video.fullscreen_mode_current)
6769 #endif
6770   {
6771     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6772
6773     /* save backbuffer content which gets lost when toggling fullscreen mode */
6774     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6775
6776 #if 1
6777     if (change_fullscreen_mode)
6778 #else
6779     if (setup.fullscreen && video.fullscreen_enabled)
6780 #endif
6781     {
6782       /* keep fullscreen, but change fullscreen mode (screen resolution) */
6783 #if 1
6784       /* (this is now set in sdl.c) */
6785 #else
6786       video.fullscreen_mode_current = setup.fullscreen_mode;
6787 #endif
6788       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
6789     }
6790
6791     /* toggle fullscreen */
6792     ChangeVideoModeIfNeeded(setup.fullscreen);
6793
6794     setup.fullscreen = video.fullscreen_enabled;
6795
6796     /* restore backbuffer content from temporary backbuffer backup bitmap */
6797     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6798
6799     FreeBitmap(tmp_backbuffer);
6800
6801 #if 1
6802     /* update visible window/screen */
6803     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6804 #else
6805     redraw_mask = REDRAW_ALL;
6806 #endif
6807   }
6808 }