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