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