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