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