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