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