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