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