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