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