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