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