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