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