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