rnd-20070917-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   {
4817     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
4818     EL_QUICKSAND_EMPTYING,              -1, -1
4819   },
4820   {
4821     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
4822     EL_QUICKSAND_EMPTYING,              -1, -1
4823   },
4824 #else
4825   {
4826     Xsand_stonesand_1,                  FALSE,  FALSE,
4827     EL_QUICKSAND_FULL,                  -1, -1
4828   },
4829   {
4830     Xsand_stonesand_2,                  FALSE,  FALSE,
4831     EL_QUICKSAND_FULL,                  -1, -1
4832   },
4833   {
4834     Xsand_stonesand_3,                  FALSE,  FALSE,
4835     EL_QUICKSAND_FULL,                  -1, -1
4836   },
4837   {
4838     Xsand_stonesand_4,                  FALSE,  FALSE,
4839     EL_QUICKSAND_FULL,                  -1, -1
4840   },
4841 #endif
4842   {
4843     Xsand_stoneout_1,                   FALSE,  FALSE,
4844     EL_ROCK,                            ACTION_EMPTYING, -1
4845   },
4846   {
4847     Xsand_stoneout_2,                   FALSE,  FALSE,
4848     EL_ROCK,                            ACTION_EMPTYING, -1
4849   },
4850 #if 1
4851   {
4852     Xsand_sandstone_1,                  FALSE,  FALSE,
4853     EL_QUICKSAND_FILLING,               -1, -1
4854   },
4855   {
4856     Xsand_sandstone_2,                  FALSE,  FALSE,
4857     EL_QUICKSAND_FILLING,               -1, -1
4858   },
4859   {
4860     Xsand_sandstone_3,                  FALSE,  FALSE,
4861     EL_QUICKSAND_FILLING,               -1, -1
4862   },
4863   {
4864     Xsand_sandstone_4,                  FALSE,  FALSE,
4865     EL_QUICKSAND_FILLING,               -1, -1
4866   },
4867 #else
4868   {
4869     Xsand_sandstone_1,                  FALSE,  FALSE,
4870     EL_QUICKSAND_FULL,                  -1, -1
4871   },
4872   {
4873     Xsand_sandstone_2,                  FALSE,  FALSE,
4874     EL_QUICKSAND_FULL,                  -1, -1
4875   },
4876   {
4877     Xsand_sandstone_3,                  FALSE,  FALSE,
4878     EL_QUICKSAND_FULL,                  -1, -1
4879   },
4880   {
4881     Xsand_sandstone_4,                  FALSE,  FALSE,
4882     EL_QUICKSAND_FULL,                  -1, -1
4883   },
4884 #endif
4885   {
4886     Xplant,                             TRUE,   FALSE,
4887     EL_EMC_PLANT,                       -1, -1
4888   },
4889   {
4890     Yplant,                             FALSE,  FALSE,
4891     EL_EMC_PLANT,                       -1, -1
4892   },
4893   {
4894     Xlenses,                            TRUE,   FALSE,
4895     EL_EMC_LENSES,                      -1, -1
4896   },
4897   {
4898     Xmagnify,                           TRUE,   FALSE,
4899     EL_EMC_MAGNIFIER,                   -1, -1
4900   },
4901   {
4902     Xdripper,                           TRUE,   FALSE,
4903     EL_EMC_DRIPPER,                     -1, -1
4904   },
4905   {
4906     XdripperB,                          FALSE,  FALSE,
4907     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4908   },
4909   {
4910     Xfake_blank,                        TRUE,   FALSE,
4911     EL_INVISIBLE_WALL,                  -1, -1
4912   },
4913   {
4914     Xfake_blankB,                       FALSE,  FALSE,
4915     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4916   },
4917   {
4918     Xfake_grass,                        TRUE,   FALSE,
4919     EL_EMC_FAKE_GRASS,                  -1, -1
4920   },
4921   {
4922     Xfake_grassB,                       FALSE,  FALSE,
4923     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4924   },
4925   {
4926     Xfake_door_1,                       TRUE,   FALSE,
4927     EL_EM_GATE_1_GRAY,                  -1, -1
4928   },
4929   {
4930     Xfake_door_2,                       TRUE,   FALSE,
4931     EL_EM_GATE_2_GRAY,                  -1, -1
4932   },
4933   {
4934     Xfake_door_3,                       TRUE,   FALSE,
4935     EL_EM_GATE_3_GRAY,                  -1, -1
4936   },
4937   {
4938     Xfake_door_4,                       TRUE,   FALSE,
4939     EL_EM_GATE_4_GRAY,                  -1, -1
4940   },
4941   {
4942     Xfake_door_5,                       TRUE,   FALSE,
4943     EL_EMC_GATE_5_GRAY,                 -1, -1
4944   },
4945   {
4946     Xfake_door_6,                       TRUE,   FALSE,
4947     EL_EMC_GATE_6_GRAY,                 -1, -1
4948   },
4949   {
4950     Xfake_door_7,                       TRUE,   FALSE,
4951     EL_EMC_GATE_7_GRAY,                 -1, -1
4952   },
4953   {
4954     Xfake_door_8,                       TRUE,   FALSE,
4955     EL_EMC_GATE_8_GRAY,                 -1, -1
4956   },
4957   {
4958     Xfake_acid_1,                       TRUE,   FALSE,
4959     EL_EMC_FAKE_ACID,                   -1, -1
4960   },
4961   {
4962     Xfake_acid_2,                       FALSE,  FALSE,
4963     EL_EMC_FAKE_ACID,                   -1, -1
4964   },
4965   {
4966     Xfake_acid_3,                       FALSE,  FALSE,
4967     EL_EMC_FAKE_ACID,                   -1, -1
4968   },
4969   {
4970     Xfake_acid_4,                       FALSE,  FALSE,
4971     EL_EMC_FAKE_ACID,                   -1, -1
4972   },
4973   {
4974     Xfake_acid_5,                       FALSE,  FALSE,
4975     EL_EMC_FAKE_ACID,                   -1, -1
4976   },
4977   {
4978     Xfake_acid_6,                       FALSE,  FALSE,
4979     EL_EMC_FAKE_ACID,                   -1, -1
4980   },
4981   {
4982     Xfake_acid_7,                       FALSE,  FALSE,
4983     EL_EMC_FAKE_ACID,                   -1, -1
4984   },
4985   {
4986     Xfake_acid_8,                       FALSE,  FALSE,
4987     EL_EMC_FAKE_ACID,                   -1, -1
4988   },
4989   {
4990     Xsteel_1,                           TRUE,   FALSE,
4991     EL_STEELWALL,                       -1, -1
4992   },
4993   {
4994     Xsteel_2,                           TRUE,   FALSE,
4995     EL_EMC_STEELWALL_2,                 -1, -1
4996   },
4997   {
4998     Xsteel_3,                           TRUE,   FALSE,
4999     EL_EMC_STEELWALL_3,                 -1, -1
5000   },
5001   {
5002     Xsteel_4,                           TRUE,   FALSE,
5003     EL_EMC_STEELWALL_4,                 -1, -1
5004   },
5005   {
5006     Xwall_1,                            TRUE,   FALSE,
5007     EL_WALL,                            -1, -1
5008   },
5009   {
5010     Xwall_2,                            TRUE,   FALSE,
5011     EL_EMC_WALL_14,                     -1, -1
5012   },
5013   {
5014     Xwall_3,                            TRUE,   FALSE,
5015     EL_EMC_WALL_15,                     -1, -1
5016   },
5017   {
5018     Xwall_4,                            TRUE,   FALSE,
5019     EL_EMC_WALL_16,                     -1, -1
5020   },
5021   {
5022     Xround_wall_1,                      TRUE,   FALSE,
5023     EL_WALL_SLIPPERY,                   -1, -1
5024   },
5025   {
5026     Xround_wall_2,                      TRUE,   FALSE,
5027     EL_EMC_WALL_SLIPPERY_2,             -1, -1
5028   },
5029   {
5030     Xround_wall_3,                      TRUE,   FALSE,
5031     EL_EMC_WALL_SLIPPERY_3,             -1, -1
5032   },
5033   {
5034     Xround_wall_4,                      TRUE,   FALSE,
5035     EL_EMC_WALL_SLIPPERY_4,             -1, -1
5036   },
5037   {
5038     Xdecor_1,                           TRUE,   FALSE,
5039     EL_EMC_WALL_8,                      -1, -1
5040   },
5041   {
5042     Xdecor_2,                           TRUE,   FALSE,
5043     EL_EMC_WALL_6,                      -1, -1
5044   },
5045   {
5046     Xdecor_3,                           TRUE,   FALSE,
5047     EL_EMC_WALL_4,                      -1, -1
5048   },
5049   {
5050     Xdecor_4,                           TRUE,   FALSE,
5051     EL_EMC_WALL_7,                      -1, -1
5052   },
5053   {
5054     Xdecor_5,                           TRUE,   FALSE,
5055     EL_EMC_WALL_5,                      -1, -1
5056   },
5057   {
5058     Xdecor_6,                           TRUE,   FALSE,
5059     EL_EMC_WALL_9,                      -1, -1
5060   },
5061   {
5062     Xdecor_7,                           TRUE,   FALSE,
5063     EL_EMC_WALL_10,                     -1, -1
5064   },
5065   {
5066     Xdecor_8,                           TRUE,   FALSE,
5067     EL_EMC_WALL_1,                      -1, -1
5068   },
5069   {
5070     Xdecor_9,                           TRUE,   FALSE,
5071     EL_EMC_WALL_2,                      -1, -1
5072   },
5073   {
5074     Xdecor_10,                          TRUE,   FALSE,
5075     EL_EMC_WALL_3,                      -1, -1
5076   },
5077   {
5078     Xdecor_11,                          TRUE,   FALSE,
5079     EL_EMC_WALL_11,                     -1, -1
5080   },
5081   {
5082     Xdecor_12,                          TRUE,   FALSE,
5083     EL_EMC_WALL_12,                     -1, -1
5084   },
5085   {
5086     Xalpha_0,                           TRUE,   FALSE,
5087     EL_CHAR('0'),                       -1, -1
5088   },
5089   {
5090     Xalpha_1,                           TRUE,   FALSE,
5091     EL_CHAR('1'),                       -1, -1
5092   },
5093   {
5094     Xalpha_2,                           TRUE,   FALSE,
5095     EL_CHAR('2'),                       -1, -1
5096   },
5097   {
5098     Xalpha_3,                           TRUE,   FALSE,
5099     EL_CHAR('3'),                       -1, -1
5100   },
5101   {
5102     Xalpha_4,                           TRUE,   FALSE,
5103     EL_CHAR('4'),                       -1, -1
5104   },
5105   {
5106     Xalpha_5,                           TRUE,   FALSE,
5107     EL_CHAR('5'),                       -1, -1
5108   },
5109   {
5110     Xalpha_6,                           TRUE,   FALSE,
5111     EL_CHAR('6'),                       -1, -1
5112   },
5113   {
5114     Xalpha_7,                           TRUE,   FALSE,
5115     EL_CHAR('7'),                       -1, -1
5116   },
5117   {
5118     Xalpha_8,                           TRUE,   FALSE,
5119     EL_CHAR('8'),                       -1, -1
5120   },
5121   {
5122     Xalpha_9,                           TRUE,   FALSE,
5123     EL_CHAR('9'),                       -1, -1
5124   },
5125   {
5126     Xalpha_excla,                       TRUE,   FALSE,
5127     EL_CHAR('!'),                       -1, -1
5128   },
5129   {
5130     Xalpha_quote,                       TRUE,   FALSE,
5131     EL_CHAR('"'),                       -1, -1
5132   },
5133   {
5134     Xalpha_comma,                       TRUE,   FALSE,
5135     EL_CHAR(','),                       -1, -1
5136   },
5137   {
5138     Xalpha_minus,                       TRUE,   FALSE,
5139     EL_CHAR('-'),                       -1, -1
5140   },
5141   {
5142     Xalpha_perio,                       TRUE,   FALSE,
5143     EL_CHAR('.'),                       -1, -1
5144   },
5145   {
5146     Xalpha_colon,                       TRUE,   FALSE,
5147     EL_CHAR(':'),                       -1, -1
5148   },
5149   {
5150     Xalpha_quest,                       TRUE,   FALSE,
5151     EL_CHAR('?'),                       -1, -1
5152   },
5153   {
5154     Xalpha_a,                           TRUE,   FALSE,
5155     EL_CHAR('A'),                       -1, -1
5156   },
5157   {
5158     Xalpha_b,                           TRUE,   FALSE,
5159     EL_CHAR('B'),                       -1, -1
5160   },
5161   {
5162     Xalpha_c,                           TRUE,   FALSE,
5163     EL_CHAR('C'),                       -1, -1
5164   },
5165   {
5166     Xalpha_d,                           TRUE,   FALSE,
5167     EL_CHAR('D'),                       -1, -1
5168   },
5169   {
5170     Xalpha_e,                           TRUE,   FALSE,
5171     EL_CHAR('E'),                       -1, -1
5172   },
5173   {
5174     Xalpha_f,                           TRUE,   FALSE,
5175     EL_CHAR('F'),                       -1, -1
5176   },
5177   {
5178     Xalpha_g,                           TRUE,   FALSE,
5179     EL_CHAR('G'),                       -1, -1
5180   },
5181   {
5182     Xalpha_h,                           TRUE,   FALSE,
5183     EL_CHAR('H'),                       -1, -1
5184   },
5185   {
5186     Xalpha_i,                           TRUE,   FALSE,
5187     EL_CHAR('I'),                       -1, -1
5188   },
5189   {
5190     Xalpha_j,                           TRUE,   FALSE,
5191     EL_CHAR('J'),                       -1, -1
5192   },
5193   {
5194     Xalpha_k,                           TRUE,   FALSE,
5195     EL_CHAR('K'),                       -1, -1
5196   },
5197   {
5198     Xalpha_l,                           TRUE,   FALSE,
5199     EL_CHAR('L'),                       -1, -1
5200   },
5201   {
5202     Xalpha_m,                           TRUE,   FALSE,
5203     EL_CHAR('M'),                       -1, -1
5204   },
5205   {
5206     Xalpha_n,                           TRUE,   FALSE,
5207     EL_CHAR('N'),                       -1, -1
5208   },
5209   {
5210     Xalpha_o,                           TRUE,   FALSE,
5211     EL_CHAR('O'),                       -1, -1
5212   },
5213   {
5214     Xalpha_p,                           TRUE,   FALSE,
5215     EL_CHAR('P'),                       -1, -1
5216   },
5217   {
5218     Xalpha_q,                           TRUE,   FALSE,
5219     EL_CHAR('Q'),                       -1, -1
5220   },
5221   {
5222     Xalpha_r,                           TRUE,   FALSE,
5223     EL_CHAR('R'),                       -1, -1
5224   },
5225   {
5226     Xalpha_s,                           TRUE,   FALSE,
5227     EL_CHAR('S'),                       -1, -1
5228   },
5229   {
5230     Xalpha_t,                           TRUE,   FALSE,
5231     EL_CHAR('T'),                       -1, -1
5232   },
5233   {
5234     Xalpha_u,                           TRUE,   FALSE,
5235     EL_CHAR('U'),                       -1, -1
5236   },
5237   {
5238     Xalpha_v,                           TRUE,   FALSE,
5239     EL_CHAR('V'),                       -1, -1
5240   },
5241   {
5242     Xalpha_w,                           TRUE,   FALSE,
5243     EL_CHAR('W'),                       -1, -1
5244   },
5245   {
5246     Xalpha_x,                           TRUE,   FALSE,
5247     EL_CHAR('X'),                       -1, -1
5248   },
5249   {
5250     Xalpha_y,                           TRUE,   FALSE,
5251     EL_CHAR('Y'),                       -1, -1
5252   },
5253   {
5254     Xalpha_z,                           TRUE,   FALSE,
5255     EL_CHAR('Z'),                       -1, -1
5256   },
5257   {
5258     Xalpha_arrow_e,                     TRUE,   FALSE,
5259     EL_CHAR('>'),                       -1, -1
5260   },
5261   {
5262     Xalpha_arrow_w,                     TRUE,   FALSE,
5263     EL_CHAR('<'),                       -1, -1
5264   },
5265   {
5266     Xalpha_copyr,                       TRUE,   FALSE,
5267     EL_CHAR('©'),                       -1, -1
5268   },
5269
5270   {
5271     Xboom_bug,                          FALSE,  FALSE,
5272     EL_BUG,                             ACTION_EXPLODING, -1
5273   },
5274   {
5275     Xboom_bomb,                         FALSE,  FALSE,
5276     EL_BOMB,                            ACTION_EXPLODING, -1
5277   },
5278   {
5279     Xboom_android,                      FALSE,  FALSE,
5280     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5281   },
5282   {
5283     Xboom_1,                            FALSE,  FALSE,
5284     EL_DEFAULT,                         ACTION_EXPLODING, -1
5285   },
5286   {
5287     Xboom_2,                            FALSE,  FALSE,
5288     EL_DEFAULT,                         ACTION_EXPLODING, -1
5289   },
5290   {
5291     Znormal,                            FALSE,  FALSE,
5292     EL_EMPTY,                           -1, -1
5293   },
5294   {
5295     Zdynamite,                          FALSE,  FALSE,
5296     EL_EMPTY,                           -1, -1
5297   },
5298   {
5299     Zplayer,                            FALSE,  FALSE,
5300     EL_EMPTY,                           -1, -1
5301   },
5302   {
5303     ZBORDER,                            FALSE,  FALSE,
5304     EL_EMPTY,                           -1, -1
5305   },
5306
5307   {
5308     -1,                                 FALSE,  FALSE,
5309     -1,                                 -1, -1
5310   }
5311 };
5312
5313 static struct Mapping_EM_to_RND_player
5314 {
5315   int action_em;
5316   int player_nr;
5317
5318   int element_rnd;
5319   int action;
5320   int direction;
5321 }
5322 em_player_mapping_list[] =
5323 {
5324   {
5325     SPR_walk + 0,                       0,
5326     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5327   },
5328   {
5329     SPR_walk + 1,                       0,
5330     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5331   },
5332   {
5333     SPR_walk + 2,                       0,
5334     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5335   },
5336   {
5337     SPR_walk + 3,                       0,
5338     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5339   },
5340   {
5341     SPR_push + 0,                       0,
5342     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5343   },
5344   {
5345     SPR_push + 1,                       0,
5346     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5347   },
5348   {
5349     SPR_push + 2,                       0,
5350     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5351   },
5352   {
5353     SPR_push + 3,                       0,
5354     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5355   },
5356   {
5357     SPR_spray + 0,                      0,
5358     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5359   },
5360   {
5361     SPR_spray + 1,                      0,
5362     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5363   },
5364   {
5365     SPR_spray + 2,                      0,
5366     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5367   },
5368   {
5369     SPR_spray + 3,                      0,
5370     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5371   },
5372   {
5373     SPR_walk + 0,                       1,
5374     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5375   },
5376   {
5377     SPR_walk + 1,                       1,
5378     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5379   },
5380   {
5381     SPR_walk + 2,                       1,
5382     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5383   },
5384   {
5385     SPR_walk + 3,                       1,
5386     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5387   },
5388   {
5389     SPR_push + 0,                       1,
5390     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5391   },
5392   {
5393     SPR_push + 1,                       1,
5394     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5395   },
5396   {
5397     SPR_push + 2,                       1,
5398     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5399   },
5400   {
5401     SPR_push + 3,                       1,
5402     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5403   },
5404   {
5405     SPR_spray + 0,                      1,
5406     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5407   },
5408   {
5409     SPR_spray + 1,                      1,
5410     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5411   },
5412   {
5413     SPR_spray + 2,                      1,
5414     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5415   },
5416   {
5417     SPR_spray + 3,                      1,
5418     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5419   },
5420   {
5421     SPR_still,                          0,
5422     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5423   },
5424   {
5425     SPR_still,                          1,
5426     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5427   },
5428   {
5429     SPR_walk + 0,                       2,
5430     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5431   },
5432   {
5433     SPR_walk + 1,                       2,
5434     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5435   },
5436   {
5437     SPR_walk + 2,                       2,
5438     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5439   },
5440   {
5441     SPR_walk + 3,                       2,
5442     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5443   },
5444   {
5445     SPR_push + 0,                       2,
5446     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5447   },
5448   {
5449     SPR_push + 1,                       2,
5450     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5451   },
5452   {
5453     SPR_push + 2,                       2,
5454     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5455   },
5456   {
5457     SPR_push + 3,                       2,
5458     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5459   },
5460   {
5461     SPR_spray + 0,                      2,
5462     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5463   },
5464   {
5465     SPR_spray + 1,                      2,
5466     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5467   },
5468   {
5469     SPR_spray + 2,                      2,
5470     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5471   },
5472   {
5473     SPR_spray + 3,                      2,
5474     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5475   },
5476   {
5477     SPR_walk + 0,                       3,
5478     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5479   },
5480   {
5481     SPR_walk + 1,                       3,
5482     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5483   },
5484   {
5485     SPR_walk + 2,                       3,
5486     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5487   },
5488   {
5489     SPR_walk + 3,                       3,
5490     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5491   },
5492   {
5493     SPR_push + 0,                       3,
5494     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5495   },
5496   {
5497     SPR_push + 1,                       3,
5498     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5499   },
5500   {
5501     SPR_push + 2,                       3,
5502     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5503   },
5504   {
5505     SPR_push + 3,                       3,
5506     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5507   },
5508   {
5509     SPR_spray + 0,                      3,
5510     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5511   },
5512   {
5513     SPR_spray + 1,                      3,
5514     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5515   },
5516   {
5517     SPR_spray + 2,                      3,
5518     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5519   },
5520   {
5521     SPR_spray + 3,                      3,
5522     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5523   },
5524   {
5525     SPR_still,                          2,
5526     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5527   },
5528   {
5529     SPR_still,                          3,
5530     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5531   },
5532
5533   {
5534     -1,                                 -1,
5535     -1,                                 -1, -1
5536   }
5537 };
5538
5539 int map_element_RND_to_EM(int element_rnd)
5540 {
5541   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5542   static boolean mapping_initialized = FALSE;
5543
5544   if (!mapping_initialized)
5545   {
5546     int i;
5547
5548     /* return "Xalpha_quest" for all undefined elements in mapping array */
5549     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5550       mapping_RND_to_EM[i] = Xalpha_quest;
5551
5552     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5553       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5554         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5555           em_object_mapping_list[i].element_em;
5556
5557     mapping_initialized = TRUE;
5558   }
5559
5560   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5561     return mapping_RND_to_EM[element_rnd];
5562
5563   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5564
5565   return EL_UNKNOWN;
5566 }
5567
5568 int map_element_EM_to_RND(int element_em)
5569 {
5570   static unsigned short mapping_EM_to_RND[TILE_MAX];
5571   static boolean mapping_initialized = FALSE;
5572
5573   if (!mapping_initialized)
5574   {
5575     int i;
5576
5577     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5578     for (i = 0; i < TILE_MAX; i++)
5579       mapping_EM_to_RND[i] = EL_UNKNOWN;
5580
5581     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5582       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5583         em_object_mapping_list[i].element_rnd;
5584
5585     mapping_initialized = TRUE;
5586   }
5587
5588   if (element_em >= 0 && element_em < TILE_MAX)
5589     return mapping_EM_to_RND[element_em];
5590
5591   Error(ERR_WARN, "invalid EM level element %d", element_em);
5592
5593   return EL_UNKNOWN;
5594 }
5595
5596 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5597 {
5598   struct LevelInfo_EM *level_em = level->native_em_level;
5599   struct LEVEL *lev = level_em->lev;
5600   int i, j;
5601
5602   for (i = 0; i < TILE_MAX; i++)
5603     lev->android_array[i] = Xblank;
5604
5605   for (i = 0; i < level->num_android_clone_elements; i++)
5606   {
5607     int element_rnd = level->android_clone_element[i];
5608     int element_em = map_element_RND_to_EM(element_rnd);
5609
5610     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5611       if (em_object_mapping_list[j].element_rnd == element_rnd)
5612         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5613   }
5614 }
5615
5616 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5617 {
5618   struct LevelInfo_EM *level_em = level->native_em_level;
5619   struct LEVEL *lev = level_em->lev;
5620   int i, j;
5621
5622   level->num_android_clone_elements = 0;
5623
5624   for (i = 0; i < TILE_MAX; i++)
5625   {
5626     int element_em = lev->android_array[i];
5627     int element_rnd;
5628     boolean element_found = FALSE;
5629
5630     if (element_em == Xblank)
5631       continue;
5632
5633     element_rnd = map_element_EM_to_RND(element_em);
5634
5635     for (j = 0; j < level->num_android_clone_elements; j++)
5636       if (level->android_clone_element[j] == element_rnd)
5637         element_found = TRUE;
5638
5639     if (!element_found)
5640     {
5641       level->android_clone_element[level->num_android_clone_elements++] =
5642         element_rnd;
5643
5644       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5645         break;
5646     }
5647   }
5648
5649   if (level->num_android_clone_elements == 0)
5650   {
5651     level->num_android_clone_elements = 1;
5652     level->android_clone_element[0] = EL_EMPTY;
5653   }
5654 }
5655
5656 int map_direction_RND_to_EM(int direction)
5657 {
5658   return (direction == MV_UP    ? 0 :
5659           direction == MV_RIGHT ? 1 :
5660           direction == MV_DOWN  ? 2 :
5661           direction == MV_LEFT  ? 3 :
5662           -1);
5663 }
5664
5665 int map_direction_EM_to_RND(int direction)
5666 {
5667   return (direction == 0 ? MV_UP    :
5668           direction == 1 ? MV_RIGHT :
5669           direction == 2 ? MV_DOWN  :
5670           direction == 3 ? MV_LEFT  :
5671           MV_NONE);
5672 }
5673
5674 int get_next_element(int element)
5675 {
5676   switch (element)
5677   {
5678     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5679     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5680     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5681     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5682     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5683     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5684     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5685     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5686     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5687     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5688     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5689
5690     default:                            return element;
5691   }
5692 }
5693
5694 #if 0
5695 int el_act_dir2img(int element, int action, int direction)
5696 {
5697   element = GFX_ELEMENT(element);
5698
5699   if (direction == MV_NONE)
5700     return element_info[element].graphic[action];
5701
5702   direction = MV_DIR_TO_BIT(direction);
5703
5704   return element_info[element].direction_graphic[action][direction];
5705 }
5706 #else
5707 int el_act_dir2img(int element, int action, int direction)
5708 {
5709   element = GFX_ELEMENT(element);
5710   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5711
5712   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5713   return element_info[element].direction_graphic[action][direction];
5714 }
5715 #endif
5716
5717 #if 0
5718 static int el_act_dir2crm(int element, int action, int direction)
5719 {
5720   element = GFX_ELEMENT(element);
5721
5722   if (direction == MV_NONE)
5723     return element_info[element].crumbled[action];
5724
5725   direction = MV_DIR_TO_BIT(direction);
5726
5727   return element_info[element].direction_crumbled[action][direction];
5728 }
5729 #else
5730 static int el_act_dir2crm(int element, int action, int direction)
5731 {
5732   element = GFX_ELEMENT(element);
5733   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5734
5735   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5736   return element_info[element].direction_crumbled[action][direction];
5737 }
5738 #endif
5739
5740 int el_act2img(int element, int action)
5741 {
5742   element = GFX_ELEMENT(element);
5743
5744   return element_info[element].graphic[action];
5745 }
5746
5747 int el_act2crm(int element, int action)
5748 {
5749   element = GFX_ELEMENT(element);
5750
5751   return element_info[element].crumbled[action];
5752 }
5753
5754 int el_dir2img(int element, int direction)
5755 {
5756   element = GFX_ELEMENT(element);
5757
5758   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5759 }
5760
5761 int el2baseimg(int element)
5762 {
5763   return element_info[element].graphic[ACTION_DEFAULT];
5764 }
5765
5766 int el2img(int element)
5767 {
5768   element = GFX_ELEMENT(element);
5769
5770   return element_info[element].graphic[ACTION_DEFAULT];
5771 }
5772
5773 int el2edimg(int element)
5774 {
5775   element = GFX_ELEMENT(element);
5776
5777   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5778 }
5779
5780 int el2preimg(int element)
5781 {
5782   element = GFX_ELEMENT(element);
5783
5784   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5785 }
5786
5787 int el2panelimg(int element)
5788 {
5789   element = GFX_ELEMENT(element);
5790
5791   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5792 }
5793
5794 int font2baseimg(int font_nr)
5795 {
5796   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5797 }
5798
5799 int getBeltNrFromBeltElement(int element)
5800 {
5801   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5802           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5803           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5804 }
5805
5806 int getBeltNrFromBeltActiveElement(int element)
5807 {
5808   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5809           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5810           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5811 }
5812
5813 int getBeltNrFromBeltSwitchElement(int element)
5814 {
5815   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5816           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5817           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5818 }
5819
5820 int getBeltDirNrFromBeltElement(int element)
5821 {
5822   static int belt_base_element[4] =
5823   {
5824     EL_CONVEYOR_BELT_1_LEFT,
5825     EL_CONVEYOR_BELT_2_LEFT,
5826     EL_CONVEYOR_BELT_3_LEFT,
5827     EL_CONVEYOR_BELT_4_LEFT
5828   };
5829
5830   int belt_nr = getBeltNrFromBeltElement(element);
5831   int belt_dir_nr = element - belt_base_element[belt_nr];
5832
5833   return (belt_dir_nr % 3);
5834 }
5835
5836 int getBeltDirNrFromBeltSwitchElement(int element)
5837 {
5838   static int belt_base_element[4] =
5839   {
5840     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5841     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5842     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5843     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5844   };
5845
5846   int belt_nr = getBeltNrFromBeltSwitchElement(element);
5847   int belt_dir_nr = element - belt_base_element[belt_nr];
5848
5849   return (belt_dir_nr % 3);
5850 }
5851
5852 int getBeltDirFromBeltElement(int element)
5853 {
5854   static int belt_move_dir[3] =
5855   {
5856     MV_LEFT,
5857     MV_NONE,
5858     MV_RIGHT
5859   };
5860
5861   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5862
5863   return belt_move_dir[belt_dir_nr];
5864 }
5865
5866 int getBeltDirFromBeltSwitchElement(int element)
5867 {
5868   static int belt_move_dir[3] =
5869   {
5870     MV_LEFT,
5871     MV_NONE,
5872     MV_RIGHT
5873   };
5874
5875   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5876
5877   return belt_move_dir[belt_dir_nr];
5878 }
5879
5880 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5881 {
5882   static int belt_base_element[4] =
5883   {
5884     EL_CONVEYOR_BELT_1_LEFT,
5885     EL_CONVEYOR_BELT_2_LEFT,
5886     EL_CONVEYOR_BELT_3_LEFT,
5887     EL_CONVEYOR_BELT_4_LEFT
5888   };
5889
5890   return belt_base_element[belt_nr] + belt_dir_nr;
5891 }
5892
5893 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5894 {
5895   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5896
5897   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5898 }
5899
5900 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5901 {
5902   static int belt_base_element[4] =
5903   {
5904     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5905     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5906     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5907     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5908   };
5909
5910   return belt_base_element[belt_nr] + belt_dir_nr;
5911 }
5912
5913 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5914 {
5915   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5916
5917   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5918 }
5919
5920 int getNumActivePlayers_EM()
5921 {
5922   int num_players = 0;
5923   int i;
5924
5925   if (!tape.playing)
5926     return -1;
5927
5928   for (i = 0; i < MAX_PLAYERS; i++)
5929     if (tape.player_participates[i])
5930       num_players++;
5931
5932   return num_players;
5933 }
5934
5935 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5936 {
5937   int game_frame_delay_value;
5938
5939   game_frame_delay_value =
5940     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5941      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5942      GameFrameDelay);
5943
5944   if (tape.playing && tape.warp_forward && !tape.pausing)
5945     game_frame_delay_value = 0;
5946
5947   return game_frame_delay_value;
5948 }
5949
5950 unsigned int InitRND(long seed)
5951 {
5952   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5953     return InitEngineRandom_EM(seed);
5954   else
5955     return InitEngineRandom_RND(seed);
5956 }
5957
5958 #if 1
5959 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5960 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5961 #endif
5962
5963 inline static int get_effective_element_EM(int tile, int frame_em)
5964 {
5965   int element             = object_mapping[tile].element_rnd;
5966   int action              = object_mapping[tile].action;
5967   boolean is_backside     = object_mapping[tile].is_backside;
5968   boolean action_removing = (action == ACTION_DIGGING ||
5969                              action == ACTION_SNAPPING ||
5970                              action == ACTION_COLLECTING);
5971
5972   if (frame_em < 7)
5973   {
5974     switch (tile)
5975     {
5976       case Yacid_splash_eB:
5977       case Yacid_splash_wB:
5978         return (frame_em > 5 ? EL_EMPTY : element);
5979
5980       default:
5981         return element;
5982     }
5983   }
5984   else  /* frame_em == 7 */
5985   {
5986     switch (tile)
5987     {
5988       case Yacid_splash_eB:
5989       case Yacid_splash_wB:
5990         return EL_EMPTY;
5991
5992       case Yemerald_stone:
5993         return EL_EMERALD;
5994
5995       case Ydiamond_stone:
5996         return EL_ROCK;
5997
5998       case Xdrip_stretch:
5999       case Xdrip_stretchB:
6000       case Ydrip_s1:
6001       case Ydrip_s1B:
6002       case Xball_1B:
6003       case Xball_2:
6004       case Xball_2B:
6005       case Yball_eat:
6006       case Ykey_1_eat:
6007       case Ykey_2_eat:
6008       case Ykey_3_eat:
6009       case Ykey_4_eat:
6010       case Ykey_5_eat:
6011       case Ykey_6_eat:
6012       case Ykey_7_eat:
6013       case Ykey_8_eat:
6014       case Ylenses_eat:
6015       case Ymagnify_eat:
6016       case Ygrass_eat:
6017       case Ydirt_eat:
6018       case Xsand_stonein_1:
6019       case Xsand_stonein_2:
6020       case Xsand_stonein_3:
6021       case Xsand_stonein_4:
6022         return element;
6023
6024       default:
6025         return (is_backside || action_removing ? EL_EMPTY : element);
6026     }
6027   }
6028 }
6029
6030 inline static boolean check_linear_animation_EM(int tile)
6031 {
6032   switch (tile)
6033   {
6034     case Xsand_stonesand_1:
6035     case Xsand_stonesand_quickout_1:
6036     case Xsand_sandstone_1:
6037     case Xsand_stonein_1:
6038     case Xsand_stoneout_1:
6039     case Xboom_1:
6040     case Xdynamite_1:
6041     case Ybug_w_n:
6042     case Ybug_n_e:
6043     case Ybug_e_s:
6044     case Ybug_s_w:
6045     case Ybug_e_n:
6046     case Ybug_s_e:
6047     case Ybug_w_s:
6048     case Ybug_n_w:
6049     case Ytank_w_n:
6050     case Ytank_n_e:
6051     case Ytank_e_s:
6052     case Ytank_s_w:
6053     case Ytank_e_n:
6054     case Ytank_s_e:
6055     case Ytank_w_s:
6056     case Ytank_n_w:
6057       return TRUE;
6058   }
6059
6060   return FALSE;
6061 }
6062
6063 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6064                                             boolean has_crumbled_graphics,
6065                                             int crumbled, int sync_frame)
6066 {
6067   /* if element can be crumbled, but certain action graphics are just empty
6068      space (like instantly snapping sand to empty space in 1 frame), do not
6069      treat these empty space graphics as crumbled graphics in EMC engine */
6070   if (crumbled == IMG_EMPTY_SPACE)
6071     has_crumbled_graphics = FALSE;
6072
6073   if (has_crumbled_graphics)
6074   {
6075     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6076     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6077                                            g_crumbled->anim_delay,
6078                                            g_crumbled->anim_mode,
6079                                            g_crumbled->anim_start_frame,
6080                                            sync_frame);
6081
6082     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6083                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6084
6085     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6086
6087     g_em->has_crumbled_graphics = TRUE;
6088   }
6089   else
6090   {
6091     g_em->crumbled_bitmap = NULL;
6092     g_em->crumbled_src_x = 0;
6093     g_em->crumbled_src_y = 0;
6094     g_em->crumbled_border_size = 0;
6095
6096     g_em->has_crumbled_graphics = FALSE;
6097   }
6098 }
6099
6100 void ResetGfxAnimation_EM(int x, int y, int tile)
6101 {
6102   GfxFrame[x][y] = 0;
6103 }
6104
6105 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6106                         int tile, int frame_em, int x, int y)
6107 {
6108   int action = object_mapping[tile].action;
6109 #if 1
6110   int direction = object_mapping[tile].direction;
6111   int effective_element = get_effective_element_EM(tile, frame_em);
6112   int graphic = (direction == MV_NONE ?
6113                  el_act2img(effective_element, action) :
6114                  el_act_dir2img(effective_element, action, direction));
6115   struct GraphicInfo *g = &graphic_info[graphic];
6116   int sync_frame;
6117 #endif
6118   boolean action_removing = (action == ACTION_DIGGING ||
6119                              action == ACTION_SNAPPING ||
6120                              action == ACTION_COLLECTING);
6121   boolean action_moving   = (action == ACTION_FALLING ||
6122                              action == ACTION_MOVING ||
6123                              action == ACTION_PUSHING ||
6124                              action == ACTION_EATING ||
6125                              action == ACTION_FILLING ||
6126                              action == ACTION_EMPTYING);
6127   boolean action_falling  = (action == ACTION_FALLING ||
6128                              action == ACTION_FILLING ||
6129                              action == ACTION_EMPTYING);
6130
6131 #if 0
6132   if (tile == Xsand_stonesand_1 ||
6133       tile == Xsand_stonesand_2 ||
6134       tile == Xsand_stonesand_3 ||
6135       tile == Xsand_stonesand_4)
6136     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6137 #endif
6138
6139 #if 1
6140   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6141   {
6142     GfxFrame[x][y] = 0;
6143
6144     // printf("::: resetting... [%d]\n", tile);
6145   }
6146 #else
6147   if (action_removing || check_linear_animation_EM(tile))
6148   {
6149     GfxFrame[x][y] = frame_em;
6150
6151     // printf("::: resetting... [%d]\n", tile);
6152   }
6153 #endif
6154   else if (action_moving)
6155   {
6156     boolean is_backside = object_mapping[tile].is_backside;
6157
6158     if (is_backside)
6159     {
6160       int direction = object_mapping[tile].direction;
6161       int move_dir = (action_falling ? MV_DOWN : direction);
6162
6163       GfxFrame[x][y]++;
6164
6165       if (move_dir == MV_LEFT)
6166         GfxFrame[x - 1][y] = GfxFrame[x][y];
6167       else if (move_dir == MV_RIGHT)
6168         GfxFrame[x + 1][y] = GfxFrame[x][y];
6169       else if (move_dir == MV_UP)
6170         GfxFrame[x][y - 1] = GfxFrame[x][y];
6171       else if (move_dir == MV_DOWN)
6172         GfxFrame[x][y + 1] = GfxFrame[x][y];
6173     }
6174   }
6175   else
6176   {
6177     GfxFrame[x][y]++;
6178
6179     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6180     if (tile == Xsand_stonesand_quickout_1 ||
6181         tile == Xsand_stonesand_quickout_2)
6182       GfxFrame[x][y]++;
6183   }
6184
6185 #if 0
6186   if (tile == Xsand_stonesand_1 ||
6187       tile == Xsand_stonesand_2 ||
6188       tile == Xsand_stonesand_3 ||
6189       tile == Xsand_stonesand_4)
6190     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6191 #endif
6192
6193 #if 1
6194   if (graphic_info[graphic].anim_global_sync)
6195     sync_frame = FrameCounter;
6196   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6197     sync_frame = GfxFrame[x][y];
6198   else
6199     sync_frame = 0;     /* playfield border (pseudo steel) */
6200
6201   SetRandomAnimationValue(x, y);
6202
6203   int frame = getAnimationFrame(g->anim_frames,
6204                                 g->anim_delay,
6205                                 g->anim_mode,
6206                                 g->anim_start_frame,
6207                                 sync_frame);
6208
6209   g_em->unique_identifier =
6210     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6211 #endif
6212 }
6213
6214 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6215                                   int tile, int frame_em, int x, int y)
6216 {
6217   int action = object_mapping[tile].action;
6218   int direction = object_mapping[tile].direction;
6219   int effective_element = get_effective_element_EM(tile, frame_em);
6220   int graphic = (direction == MV_NONE ?
6221                  el_act2img(effective_element, action) :
6222                  el_act_dir2img(effective_element, action, direction));
6223   int crumbled = (direction == MV_NONE ?
6224                   el_act2crm(effective_element, action) :
6225                   el_act_dir2crm(effective_element, action, direction));
6226   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6227   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6228   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6229   struct GraphicInfo *g = &graphic_info[graphic];
6230 #if 0
6231   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6232 #endif
6233   int sync_frame;
6234
6235 #if 0
6236   if (frame_em == 0)    /* reset animation frame for certain elements */
6237   {
6238     if (check_linear_animation_EM(tile))
6239       GfxFrame[x][y] = 0;
6240   }
6241 #endif
6242
6243   if (graphic_info[graphic].anim_global_sync)
6244     sync_frame = FrameCounter;
6245   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6246     sync_frame = GfxFrame[x][y];
6247   else
6248     sync_frame = 0;     /* playfield border (pseudo steel) */
6249
6250   SetRandomAnimationValue(x, y);
6251
6252   int frame = getAnimationFrame(g->anim_frames,
6253                                 g->anim_delay,
6254                                 g->anim_mode,
6255                                 g->anim_start_frame,
6256                                 sync_frame);
6257
6258   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6259                       &g_em->src_x, &g_em->src_y, FALSE);
6260
6261   /* (updating the "crumbled" graphic definitions is probably not really needed,
6262      as animations for crumbled graphics can't be longer than one EMC cycle) */
6263 #if 1
6264   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6265                            sync_frame);
6266
6267 #else
6268
6269   g_em->crumbled_bitmap = NULL;
6270   g_em->crumbled_src_x = 0;
6271   g_em->crumbled_src_y = 0;
6272
6273   g_em->has_crumbled_graphics = FALSE;
6274
6275   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6276   {
6277     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6278                                            g_crumbled->anim_delay,
6279                                            g_crumbled->anim_mode,
6280                                            g_crumbled->anim_start_frame,
6281                                            sync_frame);
6282
6283     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6284                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6285
6286     g_em->has_crumbled_graphics = TRUE;
6287   }
6288 #endif
6289 }
6290
6291 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6292                                   int player_nr, int anim, int frame_em)
6293 {
6294   int element   = player_mapping[player_nr][anim].element_rnd;
6295   int action    = player_mapping[player_nr][anim].action;
6296   int direction = player_mapping[player_nr][anim].direction;
6297   int graphic = (direction == MV_NONE ?
6298                  el_act2img(element, action) :
6299                  el_act_dir2img(element, action, direction));
6300   struct GraphicInfo *g = &graphic_info[graphic];
6301   int sync_frame;
6302
6303   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6304
6305   stored_player[player_nr].StepFrame = frame_em;
6306
6307   sync_frame = stored_player[player_nr].Frame;
6308
6309   int frame = getAnimationFrame(g->anim_frames,
6310                                 g->anim_delay,
6311                                 g->anim_mode,
6312                                 g->anim_start_frame,
6313                                 sync_frame);
6314
6315   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6316                       &g_em->src_x, &g_em->src_y, FALSE);
6317
6318 #if 0
6319   printf("::: %d: %d, %d [%d]\n",
6320          player_nr,
6321          stored_player[player_nr].Frame,
6322          stored_player[player_nr].StepFrame,
6323          FrameCounter);
6324 #endif
6325 }
6326
6327 void InitGraphicInfo_EM(void)
6328 {
6329 #if 0
6330   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6331   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6332 #endif
6333   int i, j, p;
6334
6335 #if DEBUG_EM_GFX
6336   int num_em_gfx_errors = 0;
6337
6338   if (graphic_info_em_object[0][0].bitmap == NULL)
6339   {
6340     /* EM graphics not yet initialized in em_open_all() */
6341
6342     return;
6343   }
6344
6345   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6346 #endif
6347
6348   /* always start with reliable default values */
6349   for (i = 0; i < TILE_MAX; i++)
6350   {
6351     object_mapping[i].element_rnd = EL_UNKNOWN;
6352     object_mapping[i].is_backside = FALSE;
6353     object_mapping[i].action = ACTION_DEFAULT;
6354     object_mapping[i].direction = MV_NONE;
6355   }
6356
6357   /* always start with reliable default values */
6358   for (p = 0; p < MAX_PLAYERS; p++)
6359   {
6360     for (i = 0; i < SPR_MAX; i++)
6361     {
6362       player_mapping[p][i].element_rnd = EL_UNKNOWN;
6363       player_mapping[p][i].action = ACTION_DEFAULT;
6364       player_mapping[p][i].direction = MV_NONE;
6365     }
6366   }
6367
6368   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6369   {
6370     int e = em_object_mapping_list[i].element_em;
6371
6372     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6373     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6374
6375     if (em_object_mapping_list[i].action != -1)
6376       object_mapping[e].action = em_object_mapping_list[i].action;
6377
6378     if (em_object_mapping_list[i].direction != -1)
6379       object_mapping[e].direction =
6380         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6381   }
6382
6383   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6384   {
6385     int a = em_player_mapping_list[i].action_em;
6386     int p = em_player_mapping_list[i].player_nr;
6387
6388     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6389
6390     if (em_player_mapping_list[i].action != -1)
6391       player_mapping[p][a].action = em_player_mapping_list[i].action;
6392
6393     if (em_player_mapping_list[i].direction != -1)
6394       player_mapping[p][a].direction =
6395         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6396   }
6397
6398   for (i = 0; i < TILE_MAX; i++)
6399   {
6400     int element = object_mapping[i].element_rnd;
6401     int action = object_mapping[i].action;
6402     int direction = object_mapping[i].direction;
6403     boolean is_backside = object_mapping[i].is_backside;
6404 #if 0
6405     boolean action_removing = (action == ACTION_DIGGING ||
6406                                action == ACTION_SNAPPING ||
6407                                action == ACTION_COLLECTING);
6408 #endif
6409     boolean action_exploding = ((action == ACTION_EXPLODING ||
6410                                  action == ACTION_SMASHED_BY_ROCK ||
6411                                  action == ACTION_SMASHED_BY_SPRING) &&
6412                                 element != EL_DIAMOND);
6413     boolean action_active = (action == ACTION_ACTIVE);
6414     boolean action_other = (action == ACTION_OTHER);
6415
6416     for (j = 0; j < 8; j++)
6417     {
6418 #if 1
6419       int effective_element = get_effective_element_EM(i, j);
6420 #else
6421       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6422                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6423                                j < 7 ? element :
6424                                i == Xdrip_stretch ? element :
6425                                i == Xdrip_stretchB ? element :
6426                                i == Ydrip_s1 ? element :
6427                                i == Ydrip_s1B ? element :
6428                                i == Xball_1B ? element :
6429                                i == Xball_2 ? element :
6430                                i == Xball_2B ? element :
6431                                i == Yball_eat ? element :
6432                                i == Ykey_1_eat ? element :
6433                                i == Ykey_2_eat ? element :
6434                                i == Ykey_3_eat ? element :
6435                                i == Ykey_4_eat ? element :
6436                                i == Ykey_5_eat ? element :
6437                                i == Ykey_6_eat ? element :
6438                                i == Ykey_7_eat ? element :
6439                                i == Ykey_8_eat ? element :
6440                                i == Ylenses_eat ? element :
6441                                i == Ymagnify_eat ? element :
6442                                i == Ygrass_eat ? element :
6443                                i == Ydirt_eat ? element :
6444                                i == Yemerald_stone ? EL_EMERALD :
6445                                i == Ydiamond_stone ? EL_ROCK :
6446                                i == Xsand_stonein_1 ? element :
6447                                i == Xsand_stonein_2 ? element :
6448                                i == Xsand_stonein_3 ? element :
6449                                i == Xsand_stonein_4 ? element :
6450                                is_backside ? EL_EMPTY :
6451                                action_removing ? EL_EMPTY :
6452                                element);
6453 #endif
6454       int effective_action = (j < 7 ? action :
6455                               i == Xdrip_stretch ? action :
6456                               i == Xdrip_stretchB ? action :
6457                               i == Ydrip_s1 ? action :
6458                               i == Ydrip_s1B ? action :
6459                               i == Xball_1B ? action :
6460                               i == Xball_2 ? action :
6461                               i == Xball_2B ? action :
6462                               i == Yball_eat ? action :
6463                               i == Ykey_1_eat ? action :
6464                               i == Ykey_2_eat ? action :
6465                               i == Ykey_3_eat ? action :
6466                               i == Ykey_4_eat ? action :
6467                               i == Ykey_5_eat ? action :
6468                               i == Ykey_6_eat ? action :
6469                               i == Ykey_7_eat ? action :
6470                               i == Ykey_8_eat ? action :
6471                               i == Ylenses_eat ? action :
6472                               i == Ymagnify_eat ? action :
6473                               i == Ygrass_eat ? action :
6474                               i == Ydirt_eat ? action :
6475                               i == Xsand_stonein_1 ? action :
6476                               i == Xsand_stonein_2 ? action :
6477                               i == Xsand_stonein_3 ? action :
6478                               i == Xsand_stonein_4 ? action :
6479                               i == Xsand_stoneout_1 ? action :
6480                               i == Xsand_stoneout_2 ? action :
6481                               i == Xboom_android ? ACTION_EXPLODING :
6482                               action_exploding ? ACTION_EXPLODING :
6483                               action_active ? action :
6484                               action_other ? action :
6485                               ACTION_DEFAULT);
6486       int graphic = (el_act_dir2img(effective_element, effective_action,
6487                                     direction));
6488       int crumbled = (el_act_dir2crm(effective_element, effective_action,
6489                                      direction));
6490       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6491       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6492       boolean has_action_graphics = (graphic != base_graphic);
6493       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6494       struct GraphicInfo *g = &graphic_info[graphic];
6495 #if 0
6496       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6497 #endif
6498       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6499       Bitmap *src_bitmap;
6500       int src_x, src_y;
6501       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6502       boolean special_animation = (action != ACTION_DEFAULT &&
6503                                    g->anim_frames == 3 &&
6504                                    g->anim_delay == 2 &&
6505                                    g->anim_mode & ANIM_LINEAR);
6506       int sync_frame = (i == Xdrip_stretch ? 7 :
6507                         i == Xdrip_stretchB ? 7 :
6508                         i == Ydrip_s2 ? j + 8 :
6509                         i == Ydrip_s2B ? j + 8 :
6510                         i == Xacid_1 ? 0 :
6511                         i == Xacid_2 ? 10 :
6512                         i == Xacid_3 ? 20 :
6513                         i == Xacid_4 ? 30 :
6514                         i == Xacid_5 ? 40 :
6515                         i == Xacid_6 ? 50 :
6516                         i == Xacid_7 ? 60 :
6517                         i == Xacid_8 ? 70 :
6518                         i == Xfake_acid_1 ? 0 :
6519                         i == Xfake_acid_2 ? 10 :
6520                         i == Xfake_acid_3 ? 20 :
6521                         i == Xfake_acid_4 ? 30 :
6522                         i == Xfake_acid_5 ? 40 :
6523                         i == Xfake_acid_6 ? 50 :
6524                         i == Xfake_acid_7 ? 60 :
6525                         i == Xfake_acid_8 ? 70 :
6526                         i == Xball_2 ? 7 :
6527                         i == Xball_2B ? j + 8 :
6528                         i == Yball_eat ? j + 1 :
6529                         i == Ykey_1_eat ? j + 1 :
6530                         i == Ykey_2_eat ? j + 1 :
6531                         i == Ykey_3_eat ? j + 1 :
6532                         i == Ykey_4_eat ? j + 1 :
6533                         i == Ykey_5_eat ? j + 1 :
6534                         i == Ykey_6_eat ? j + 1 :
6535                         i == Ykey_7_eat ? j + 1 :
6536                         i == Ykey_8_eat ? j + 1 :
6537                         i == Ylenses_eat ? j + 1 :
6538                         i == Ymagnify_eat ? j + 1 :
6539                         i == Ygrass_eat ? j + 1 :
6540                         i == Ydirt_eat ? j + 1 :
6541                         i == Xamoeba_1 ? 0 :
6542                         i == Xamoeba_2 ? 1 :
6543                         i == Xamoeba_3 ? 2 :
6544                         i == Xamoeba_4 ? 3 :
6545                         i == Xamoeba_5 ? 0 :
6546                         i == Xamoeba_6 ? 1 :
6547                         i == Xamoeba_7 ? 2 :
6548                         i == Xamoeba_8 ? 3 :
6549                         i == Xexit_2 ? j + 8 :
6550                         i == Xexit_3 ? j + 16 :
6551                         i == Xdynamite_1 ? 0 :
6552                         i == Xdynamite_2 ? 8 :
6553                         i == Xdynamite_3 ? 16 :
6554                         i == Xdynamite_4 ? 24 :
6555                         i == Xsand_stonein_1 ? j + 1 :
6556                         i == Xsand_stonein_2 ? j + 9 :
6557                         i == Xsand_stonein_3 ? j + 17 :
6558                         i == Xsand_stonein_4 ? j + 25 :
6559                         i == Xsand_stoneout_1 && j == 0 ? 0 :
6560                         i == Xsand_stoneout_1 && j == 1 ? 0 :
6561                         i == Xsand_stoneout_1 && j == 2 ? 1 :
6562                         i == Xsand_stoneout_1 && j == 3 ? 2 :
6563                         i == Xsand_stoneout_1 && j == 4 ? 2 :
6564                         i == Xsand_stoneout_1 && j == 5 ? 3 :
6565                         i == Xsand_stoneout_1 && j == 6 ? 4 :
6566                         i == Xsand_stoneout_1 && j == 7 ? 4 :
6567                         i == Xsand_stoneout_2 && j == 0 ? 5 :
6568                         i == Xsand_stoneout_2 && j == 1 ? 6 :
6569                         i == Xsand_stoneout_2 && j == 2 ? 7 :
6570                         i == Xsand_stoneout_2 && j == 3 ? 8 :
6571                         i == Xsand_stoneout_2 && j == 4 ? 9 :
6572                         i == Xsand_stoneout_2 && j == 5 ? 11 :
6573                         i == Xsand_stoneout_2 && j == 6 ? 13 :
6574                         i == Xsand_stoneout_2 && j == 7 ? 15 :
6575                         i == Xboom_bug && j == 1 ? 2 :
6576                         i == Xboom_bug && j == 2 ? 2 :
6577                         i == Xboom_bug && j == 3 ? 4 :
6578                         i == Xboom_bug && j == 4 ? 4 :
6579                         i == Xboom_bug && j == 5 ? 2 :
6580                         i == Xboom_bug && j == 6 ? 2 :
6581                         i == Xboom_bug && j == 7 ? 0 :
6582                         i == Xboom_bomb && j == 1 ? 2 :
6583                         i == Xboom_bomb && j == 2 ? 2 :
6584                         i == Xboom_bomb && j == 3 ? 4 :
6585                         i == Xboom_bomb && j == 4 ? 4 :
6586                         i == Xboom_bomb && j == 5 ? 2 :
6587                         i == Xboom_bomb && j == 6 ? 2 :
6588                         i == Xboom_bomb && j == 7 ? 0 :
6589                         i == Xboom_android && j == 7 ? 6 :
6590                         i == Xboom_1 && j == 1 ? 2 :
6591                         i == Xboom_1 && j == 2 ? 2 :
6592                         i == Xboom_1 && j == 3 ? 4 :
6593                         i == Xboom_1 && j == 4 ? 4 :
6594                         i == Xboom_1 && j == 5 ? 6 :
6595                         i == Xboom_1 && j == 6 ? 6 :
6596                         i == Xboom_1 && j == 7 ? 8 :
6597                         i == Xboom_2 && j == 0 ? 8 :
6598                         i == Xboom_2 && j == 1 ? 8 :
6599                         i == Xboom_2 && j == 2 ? 10 :
6600                         i == Xboom_2 && j == 3 ? 10 :
6601                         i == Xboom_2 && j == 4 ? 10 :
6602                         i == Xboom_2 && j == 5 ? 12 :
6603                         i == Xboom_2 && j == 6 ? 12 :
6604                         i == Xboom_2 && j == 7 ? 12 :
6605                         special_animation && j == 4 ? 3 :
6606                         effective_action != action ? 0 :
6607                         j);
6608
6609 #if DEBUG_EM_GFX
6610       Bitmap *debug_bitmap = g_em->bitmap;
6611       int debug_src_x = g_em->src_x;
6612       int debug_src_y = g_em->src_y;
6613 #endif
6614
6615       int frame = getAnimationFrame(g->anim_frames,
6616                                     g->anim_delay,
6617                                     g->anim_mode,
6618                                     g->anim_start_frame,
6619                                     sync_frame);
6620
6621       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6622                           g->double_movement && is_backside);
6623
6624       g_em->bitmap = src_bitmap;
6625       g_em->src_x = src_x;
6626       g_em->src_y = src_y;
6627       g_em->src_offset_x = 0;
6628       g_em->src_offset_y = 0;
6629       g_em->dst_offset_x = 0;
6630       g_em->dst_offset_y = 0;
6631       g_em->width  = TILEX;
6632       g_em->height = TILEY;
6633
6634       g_em->preserve_background = FALSE;
6635
6636 #if 1
6637       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6638                                sync_frame);
6639
6640 #else
6641
6642       g_em->crumbled_bitmap = NULL;
6643       g_em->crumbled_src_x = 0;
6644       g_em->crumbled_src_y = 0;
6645       g_em->crumbled_border_size = 0;
6646
6647       g_em->has_crumbled_graphics = FALSE;
6648
6649 #if 0
6650       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6651         printf("::: empty crumbled: %d [%s], %d, %d\n",
6652                effective_element, element_info[effective_element].token_name,
6653                effective_action, direction);
6654 #endif
6655
6656       /* if element can be crumbled, but certain action graphics are just empty
6657          space (like instantly snapping sand to empty space in 1 frame), do not
6658          treat these empty space graphics as crumbled graphics in EMC engine */
6659       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6660       {
6661         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6662                                                g_crumbled->anim_delay,
6663                                                g_crumbled->anim_mode,
6664                                                g_crumbled->anim_start_frame,
6665                                                sync_frame);
6666
6667         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6668
6669         g_em->has_crumbled_graphics = TRUE;
6670         g_em->crumbled_bitmap = src_bitmap;
6671         g_em->crumbled_src_x = src_x;
6672         g_em->crumbled_src_y = src_y;
6673         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6674
6675
6676 #if 0
6677         if (g_em == &graphic_info_em_object[207][0])
6678           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6679                  graphic_info_em_object[207][0].crumbled_src_x,
6680                  graphic_info_em_object[207][0].crumbled_src_y,
6681
6682                  crumbled, frame, src_x, src_y,
6683
6684                  g->anim_frames,
6685                  g->anim_delay,
6686                  g->anim_mode,
6687                  g->anim_start_frame,
6688                  sync_frame,
6689                  gfx.anim_random_frame,
6690                  frame);
6691 #endif
6692
6693 #if 0
6694         printf("::: EMC tile %d is crumbled\n", i);
6695 #endif
6696       }
6697 #endif
6698
6699 #if 0
6700       if (element == EL_ROCK &&
6701           effective_action == ACTION_FILLING)
6702         printf("::: has_action_graphics == %d\n", has_action_graphics);
6703 #endif
6704
6705       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6706                                    effective_action == ACTION_MOVING  ||
6707                                    effective_action == ACTION_PUSHING ||
6708                                    effective_action == ACTION_EATING)) ||
6709           (!has_action_graphics && (effective_action == ACTION_FILLING ||
6710                                     effective_action == ACTION_EMPTYING)))
6711       {
6712         int move_dir =
6713           (effective_action == ACTION_FALLING ||
6714            effective_action == ACTION_FILLING ||
6715            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6716         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6717         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
6718         int num_steps = (i == Ydrip_s1  ? 16 :
6719                          i == Ydrip_s1B ? 16 :
6720                          i == Ydrip_s2  ? 16 :
6721                          i == Ydrip_s2B ? 16 :
6722                          i == Xsand_stonein_1 ? 32 :
6723                          i == Xsand_stonein_2 ? 32 :
6724                          i == Xsand_stonein_3 ? 32 :
6725                          i == Xsand_stonein_4 ? 32 :
6726                          i == Xsand_stoneout_1 ? 16 :
6727                          i == Xsand_stoneout_2 ? 16 : 8);
6728         int cx = ABS(dx) * (TILEX / num_steps);
6729         int cy = ABS(dy) * (TILEY / num_steps);
6730         int step_frame = (i == Ydrip_s2         ? j + 8 :
6731                           i == Ydrip_s2B        ? j + 8 :
6732                           i == Xsand_stonein_2  ? j + 8 :
6733                           i == Xsand_stonein_3  ? j + 16 :
6734                           i == Xsand_stonein_4  ? j + 24 :
6735                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6736         int step = (is_backside ? step_frame : num_steps - step_frame);
6737
6738         if (is_backside)        /* tile where movement starts */
6739         {
6740           if (dx < 0 || dy < 0)
6741           {
6742             g_em->src_offset_x = cx * step;
6743             g_em->src_offset_y = cy * step;
6744           }
6745           else
6746           {
6747             g_em->dst_offset_x = cx * step;
6748             g_em->dst_offset_y = cy * step;
6749           }
6750         }
6751         else                    /* tile where movement ends */
6752         {
6753           if (dx < 0 || dy < 0)
6754           {
6755             g_em->dst_offset_x = cx * step;
6756             g_em->dst_offset_y = cy * step;
6757           }
6758           else
6759           {
6760             g_em->src_offset_x = cx * step;
6761             g_em->src_offset_y = cy * step;
6762           }
6763         }
6764
6765         g_em->width  = TILEX - cx * step;
6766         g_em->height = TILEY - cy * step;
6767       }
6768
6769       /* create unique graphic identifier to decide if tile must be redrawn */
6770       /* bit 31 - 16 (16 bit): EM style graphic
6771          bit 15 - 12 ( 4 bit): EM style frame
6772          bit 11 -  6 ( 6 bit): graphic width
6773          bit  5 -  0 ( 6 bit): graphic height */
6774       g_em->unique_identifier =
6775         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6776
6777 #if DEBUG_EM_GFX
6778
6779       /* skip check for EMC elements not contained in original EMC artwork */
6780       if (element == EL_EMC_FAKE_ACID)
6781         continue;
6782
6783       if (g_em->bitmap != debug_bitmap ||
6784           g_em->src_x != debug_src_x ||
6785           g_em->src_y != debug_src_y ||
6786           g_em->src_offset_x != 0 ||
6787           g_em->src_offset_y != 0 ||
6788           g_em->dst_offset_x != 0 ||
6789           g_em->dst_offset_y != 0 ||
6790           g_em->width != TILEX ||
6791           g_em->height != TILEY)
6792       {
6793         static int last_i = -1;
6794
6795         if (i != last_i)
6796         {
6797           printf("\n");
6798           last_i = i;
6799         }
6800
6801         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6802                i, element, element_info[element].token_name,
6803                element_action_info[effective_action].suffix, direction);
6804
6805         if (element != effective_element)
6806           printf(" [%d ('%s')]",
6807                  effective_element,
6808                  element_info[effective_element].token_name);
6809
6810         printf("\n");
6811
6812         if (g_em->bitmap != debug_bitmap)
6813           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6814                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6815
6816         if (g_em->src_x != debug_src_x ||
6817             g_em->src_y != debug_src_y)
6818           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6819                  j, (is_backside ? 'B' : 'F'),
6820                  g_em->src_x, g_em->src_y,
6821                  g_em->src_x / 32, g_em->src_y / 32,
6822                  debug_src_x, debug_src_y,
6823                  debug_src_x / 32, debug_src_y / 32);
6824
6825         if (g_em->src_offset_x != 0 ||
6826             g_em->src_offset_y != 0 ||
6827             g_em->dst_offset_x != 0 ||
6828             g_em->dst_offset_y != 0)
6829           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6830                  j, is_backside,
6831                  g_em->src_offset_x, g_em->src_offset_y,
6832                  g_em->dst_offset_x, g_em->dst_offset_y);
6833
6834         if (g_em->width != TILEX ||
6835             g_em->height != TILEY)
6836           printf("    %d (%d): size %d,%d should be %d,%d\n",
6837                  j, is_backside,
6838                  g_em->width, g_em->height, TILEX, TILEY);
6839
6840         num_em_gfx_errors++;
6841       }
6842 #endif
6843
6844     }
6845   }
6846
6847   for (i = 0; i < TILE_MAX; i++)
6848   {
6849     for (j = 0; j < 8; j++)
6850     {
6851       int element = object_mapping[i].element_rnd;
6852       int action = object_mapping[i].action;
6853       int direction = object_mapping[i].direction;
6854       boolean is_backside = object_mapping[i].is_backside;
6855       int graphic_action  = el_act_dir2img(element, action, direction);
6856       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6857
6858       if ((action == ACTION_SMASHED_BY_ROCK ||
6859            action == ACTION_SMASHED_BY_SPRING ||
6860            action == ACTION_EATING) &&
6861           graphic_action == graphic_default)
6862       {
6863         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6864                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6865                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6866                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6867                  Xspring);
6868
6869         /* no separate animation for "smashed by rock" -- use rock instead */
6870         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6871         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6872
6873         g_em->bitmap            = g_xx->bitmap;
6874         g_em->src_x             = g_xx->src_x;
6875         g_em->src_y             = g_xx->src_y;
6876         g_em->src_offset_x      = g_xx->src_offset_x;
6877         g_em->src_offset_y      = g_xx->src_offset_y;
6878         g_em->dst_offset_x      = g_xx->dst_offset_x;
6879         g_em->dst_offset_y      = g_xx->dst_offset_y;
6880         g_em->width             = g_xx->width;
6881         g_em->height            = g_xx->height;
6882         g_em->unique_identifier = g_xx->unique_identifier;
6883
6884         if (!is_backside)
6885           g_em->preserve_background = TRUE;
6886       }
6887     }
6888   }
6889
6890   for (p = 0; p < MAX_PLAYERS; p++)
6891   {
6892     for (i = 0; i < SPR_MAX; i++)
6893     {
6894       int element = player_mapping[p][i].element_rnd;
6895       int action = player_mapping[p][i].action;
6896       int direction = player_mapping[p][i].direction;
6897
6898       for (j = 0; j < 8; j++)
6899       {
6900         int effective_element = element;
6901         int effective_action = action;
6902         int graphic = (direction == MV_NONE ?
6903                        el_act2img(effective_element, effective_action) :
6904                        el_act_dir2img(effective_element, effective_action,
6905                                       direction));
6906         struct GraphicInfo *g = &graphic_info[graphic];
6907         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6908         Bitmap *src_bitmap;
6909         int src_x, src_y;
6910         int sync_frame = j;
6911
6912 #if DEBUG_EM_GFX
6913         Bitmap *debug_bitmap = g_em->bitmap;
6914         int debug_src_x = g_em->src_x;
6915         int debug_src_y = g_em->src_y;
6916 #endif
6917
6918         int frame = getAnimationFrame(g->anim_frames,
6919                                       g->anim_delay,
6920                                       g->anim_mode,
6921                                       g->anim_start_frame,
6922                                       sync_frame);
6923
6924         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6925
6926         g_em->bitmap = src_bitmap;
6927         g_em->src_x = src_x;
6928         g_em->src_y = src_y;
6929         g_em->src_offset_x = 0;
6930         g_em->src_offset_y = 0;
6931         g_em->dst_offset_x = 0;
6932         g_em->dst_offset_y = 0;
6933         g_em->width  = TILEX;
6934         g_em->height = TILEY;
6935
6936 #if DEBUG_EM_GFX
6937
6938         /* skip check for EMC elements not contained in original EMC artwork */
6939         if (element == EL_PLAYER_3 ||
6940             element == EL_PLAYER_4)
6941           continue;
6942
6943         if (g_em->bitmap != debug_bitmap ||
6944             g_em->src_x != debug_src_x ||
6945             g_em->src_y != debug_src_y)
6946         {
6947           static int last_i = -1;
6948
6949           if (i != last_i)
6950           {
6951             printf("\n");
6952             last_i = i;
6953           }
6954
6955           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6956                  p, i, element, element_info[element].token_name,
6957                  element_action_info[effective_action].suffix, direction);
6958
6959           if (element != effective_element)
6960             printf(" [%d ('%s')]",
6961                    effective_element,
6962                    element_info[effective_element].token_name);
6963
6964           printf("\n");
6965
6966           if (g_em->bitmap != debug_bitmap)
6967             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6968                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6969
6970           if (g_em->src_x != debug_src_x ||
6971               g_em->src_y != debug_src_y)
6972             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6973                    j,
6974                    g_em->src_x, g_em->src_y,
6975                    g_em->src_x / 32, g_em->src_y / 32,
6976                    debug_src_x, debug_src_y,
6977                    debug_src_x / 32, debug_src_y / 32);
6978
6979           num_em_gfx_errors++;
6980         }
6981 #endif
6982
6983       }
6984     }
6985   }
6986
6987 #if DEBUG_EM_GFX
6988   printf("\n");
6989   printf("::: [%d errors found]\n", num_em_gfx_errors);
6990
6991   exit(0);
6992 #endif
6993 }
6994
6995 void PlayMenuSoundExt(int sound)
6996 {
6997   if (sound == SND_UNDEFINED)
6998     return;
6999
7000   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7001       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7002     return;
7003
7004   if (IS_LOOP_SOUND(sound))
7005     PlaySoundLoop(sound);
7006   else
7007     PlaySound(sound);
7008 }
7009
7010 void PlayMenuSound()
7011 {
7012   PlayMenuSoundExt(menu.sound[game_status]);
7013 }
7014
7015 void PlayMenuSoundStereo(int sound, int stereo_position)
7016 {
7017   if (sound == SND_UNDEFINED)
7018     return;
7019
7020   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7021       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7022     return;
7023
7024   if (IS_LOOP_SOUND(sound))
7025     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7026   else
7027     PlaySoundStereo(sound, stereo_position);
7028 }
7029
7030 void PlayMenuSoundIfLoopExt(int sound)
7031 {
7032   if (sound == SND_UNDEFINED)
7033     return;
7034
7035   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7036       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7037     return;
7038
7039   if (IS_LOOP_SOUND(sound))
7040     PlaySoundLoop(sound);
7041 }
7042
7043 void PlayMenuSoundIfLoop()
7044 {
7045   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7046 }
7047
7048 void PlayMenuMusicExt(int music)
7049 {
7050   if (music == MUS_UNDEFINED)
7051     return;
7052
7053   if (!setup.sound_music)
7054     return;
7055
7056   PlayMusic(music);
7057 }
7058
7059 void PlayMenuMusic()
7060 {
7061   PlayMenuMusicExt(menu.music[game_status]);
7062 }
7063
7064 void PlaySoundActivating()
7065 {
7066 #if 0
7067   PlaySound(SND_MENU_ITEM_ACTIVATING);
7068 #endif
7069 }
7070
7071 void PlaySoundSelecting()
7072 {
7073 #if 0
7074   PlaySound(SND_MENU_ITEM_SELECTING);
7075 #endif
7076 }
7077
7078 void ToggleFullscreenIfNeeded()
7079 {
7080   boolean change_fullscreen = (setup.fullscreen !=
7081                                video.fullscreen_enabled);
7082   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7083                                     !strEqual(setup.fullscreen_mode,
7084                                               video.fullscreen_mode_current));
7085
7086   if (!video.fullscreen_available)
7087     return;
7088
7089 #if 1
7090   if (change_fullscreen || change_fullscreen_mode)
7091 #else
7092   if (setup.fullscreen != video.fullscreen_enabled ||
7093       setup.fullscreen_mode != video.fullscreen_mode_current)
7094 #endif
7095   {
7096     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7097
7098     /* save backbuffer content which gets lost when toggling fullscreen mode */
7099     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7100
7101 #if 1
7102     if (change_fullscreen_mode)
7103 #else
7104     if (setup.fullscreen && video.fullscreen_enabled)
7105 #endif
7106     {
7107       /* keep fullscreen, but change fullscreen mode (screen resolution) */
7108 #if 1
7109       /* (this is now set in sdl.c) */
7110 #else
7111       video.fullscreen_mode_current = setup.fullscreen_mode;
7112 #endif
7113       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
7114     }
7115
7116     /* toggle fullscreen */
7117     ChangeVideoModeIfNeeded(setup.fullscreen);
7118
7119     setup.fullscreen = video.fullscreen_enabled;
7120
7121     /* restore backbuffer content from temporary backbuffer backup bitmap */
7122     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7123
7124     FreeBitmap(tmp_backbuffer);
7125
7126 #if 1
7127     /* update visible window/screen */
7128     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7129 #else
7130     redraw_mask = REDRAW_ALL;
7131 #endif
7132   }
7133 }