rnd-20070401-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "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_Return:
2942               result = 1;
2943               break;
2944
2945             case KSYM_Escape:
2946               result = 0;
2947               break;
2948
2949             default:
2950               break;
2951           }
2952           if (req_state & REQ_PLAYER)
2953             result = 0;
2954           break;
2955
2956         case EVENT_KEYRELEASE:
2957           ClearPlayerAction();
2958           break;
2959
2960         default:
2961           HandleOtherEvents(&event);
2962           break;
2963       }
2964     }
2965     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2966     {
2967       int joy = AnyJoystick();
2968
2969       if (joy & JOY_BUTTON_1)
2970         result = 1;
2971       else if (joy & JOY_BUTTON_2)
2972         result = 0;
2973     }
2974
2975 #if 1
2976
2977     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2978     {
2979       HandleGameActions();
2980       BackToFront();
2981     }
2982     else
2983     {
2984       DoAnimation();
2985
2986       if (!PendingEvent())      /* delay only if no pending events */
2987         Delay(10);
2988     }
2989
2990 #else
2991
2992     DoAnimation();
2993
2994 #if 1
2995     if (!PendingEvent())        /* delay only if no pending events */
2996       Delay(10);
2997 #else
2998     /* don't eat all CPU time */
2999     Delay(10);
3000 #endif
3001
3002 #endif
3003   }
3004
3005   if (game_status != GAME_MODE_MAIN)
3006     StopAnimation();
3007
3008   UnmapToolButtons();
3009
3010   if (!(req_state & REQ_STAY_OPEN))
3011   {
3012     CloseDoor(DOOR_CLOSE_1);
3013
3014     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3015         (req_state & REQ_REOPEN))
3016       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3017   }
3018
3019   RemapAllGadgets();
3020
3021   if (game_status == GAME_MODE_PLAYING)
3022   {
3023     SetPanelBackground();
3024     SetDrawBackgroundMask(REDRAW_DOOR_1);
3025   }
3026   else
3027   {
3028     SetDrawBackgroundMask(REDRAW_FIELD);
3029   }
3030
3031 #if defined(NETWORK_AVALIABLE)
3032   /* continue network game after request */
3033   if (options.network &&
3034       game_status == GAME_MODE_PLAYING &&
3035       req_state & REQUEST_WAIT_FOR_INPUT)
3036     SendToServer_ContinuePlaying();
3037 #endif
3038
3039   /* restore deactivated drawing when quick-loading level tape recording */
3040   if (tape.playing && tape.deactivate_display)
3041     TapeDeactivateDisplayOn();
3042
3043   return result;
3044 }
3045
3046 unsigned int OpenDoor(unsigned int door_state)
3047 {
3048   if (door_state & DOOR_COPY_BACK)
3049   {
3050     if (door_state & DOOR_OPEN_1)
3051       BlitBitmap(bitmap_db_door, bitmap_db_door,
3052                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3053                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3054
3055     if (door_state & DOOR_OPEN_2)
3056       BlitBitmap(bitmap_db_door, bitmap_db_door,
3057                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3058                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3059
3060     door_state &= ~DOOR_COPY_BACK;
3061   }
3062
3063   return MoveDoor(door_state);
3064 }
3065
3066 unsigned int CloseDoor(unsigned int door_state)
3067 {
3068   unsigned int old_door_state = GetDoorState();
3069
3070   if (!(door_state & DOOR_NO_COPY_BACK))
3071   {
3072     if (old_door_state & DOOR_OPEN_1)
3073       BlitBitmap(backbuffer, bitmap_db_door,
3074                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3075
3076     if (old_door_state & DOOR_OPEN_2)
3077       BlitBitmap(backbuffer, bitmap_db_door,
3078                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3079
3080     door_state &= ~DOOR_NO_COPY_BACK;
3081   }
3082
3083   return MoveDoor(door_state);
3084 }
3085
3086 unsigned int GetDoorState()
3087 {
3088   return MoveDoor(DOOR_GET_STATE);
3089 }
3090
3091 unsigned int SetDoorState(unsigned int door_state)
3092 {
3093   return MoveDoor(door_state | DOOR_SET_STATE);
3094 }
3095
3096 unsigned int MoveDoor(unsigned int door_state)
3097 {
3098   static int door1 = DOOR_OPEN_1;
3099   static int door2 = DOOR_CLOSE_2;
3100   unsigned long door_delay = 0;
3101   unsigned long door_delay_value;
3102   int stepsize = 1;
3103
3104   if (door_1.width < 0 || door_1.width > DXSIZE)
3105     door_1.width = DXSIZE;
3106   if (door_1.height < 0 || door_1.height > DYSIZE)
3107     door_1.height = DYSIZE;
3108   if (door_2.width < 0 || door_2.width > VXSIZE)
3109     door_2.width = VXSIZE;
3110   if (door_2.height < 0 || door_2.height > VYSIZE)
3111     door_2.height = VYSIZE;
3112
3113   if (door_state == DOOR_GET_STATE)
3114     return (door1 | door2);
3115
3116   if (door_state & DOOR_SET_STATE)
3117   {
3118     if (door_state & DOOR_ACTION_1)
3119       door1 = door_state & DOOR_ACTION_1;
3120     if (door_state & DOOR_ACTION_2)
3121       door2 = door_state & DOOR_ACTION_2;
3122
3123     return (door1 | door2);
3124   }
3125
3126   if (!(door_state & DOOR_FORCE_REDRAW))
3127   {
3128     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3129       door_state &= ~DOOR_OPEN_1;
3130     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3131       door_state &= ~DOOR_CLOSE_1;
3132     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3133       door_state &= ~DOOR_OPEN_2;
3134     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3135       door_state &= ~DOOR_CLOSE_2;
3136   }
3137
3138   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3139                       door_2.step_delay);
3140
3141   if (setup.quick_doors)
3142   {
3143     stepsize = 20;              /* must be chosen to always draw last frame */
3144     door_delay_value = 0;
3145   }
3146
3147   if (global.autoplay_leveldir)
3148   {
3149     door_state |= DOOR_NO_DELAY;
3150     door_state &= ~DOOR_CLOSE_ALL;
3151   }
3152
3153   if (door_state & DOOR_ACTION)
3154   {
3155     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3156     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3157     boolean door_1_done = (!handle_door_1);
3158     boolean door_2_done = (!handle_door_2);
3159     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3160     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3161     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3162     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3163     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3164     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3165     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
3166     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3167     int door_skip = max_door_size - door_size;
3168     int end = door_size;
3169     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3170     int k;
3171
3172     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3173     {
3174       /* opening door sound has priority over simultaneously closing door */
3175       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3176         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3177       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3178         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3179     }
3180
3181     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3182     {
3183       int x = k;
3184       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3185       GC gc = bitmap->stored_clip_gc;
3186
3187       if (door_state & DOOR_ACTION_1)
3188       {
3189         int a = MIN(x * door_1.step_offset, end);
3190         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3191         int i = p + door_skip;
3192
3193         if (door_1.anim_mode & ANIM_STATIC_PANEL)
3194         {
3195           BlitBitmap(bitmap_db_door, drawto,
3196                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3197                      DXSIZE, DYSIZE, DX, DY);
3198         }
3199         else if (x <= a)
3200         {
3201           BlitBitmap(bitmap_db_door, drawto,
3202                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3203                      DXSIZE, DYSIZE - p / 2, DX, DY);
3204
3205           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3206         }
3207
3208         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3209         {
3210           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3211           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3212           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
3213           int dst2_x = DX,              dst2_y = DY;
3214           int width = i, height = DYSIZE;
3215
3216           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3217           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3218                            dst1_x, dst1_y);
3219
3220           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3221           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3222                            dst2_x, dst2_y);
3223         }
3224         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3225         {
3226           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3227           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
3228           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3229           int dst2_x = DX,              dst2_y = DY;
3230           int width = DXSIZE, height = i;
3231
3232           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3233           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3234                            dst1_x, dst1_y);
3235
3236           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3237           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3238                            dst2_x, dst2_y);
3239         }
3240         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
3241         {
3242           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3243
3244           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3245           BlitBitmapMasked(bitmap, drawto,
3246                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3247                            DX + DXSIZE - i, DY + j);
3248           BlitBitmapMasked(bitmap, drawto,
3249                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3250                            DX + DXSIZE - i, DY + 140 + j);
3251           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3252                         DY - (DOOR_GFX_PAGEY1 + j));
3253           BlitBitmapMasked(bitmap, drawto,
3254                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3255                            DX, DY);
3256           BlitBitmapMasked(bitmap, drawto,
3257                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3258                            DX, DY + 140 - j);
3259
3260           BlitBitmapMasked(bitmap, drawto,
3261                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3262                            DX, DY + 77 - j);
3263           BlitBitmapMasked(bitmap, drawto,
3264                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3265                            DX, DY + 203 - j);
3266           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3267           BlitBitmapMasked(bitmap, drawto,
3268                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3269                            DX + DXSIZE - i, DY + 77 + j);
3270           BlitBitmapMasked(bitmap, drawto,
3271                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3272                            DX + DXSIZE - i, DY + 203 + j);
3273         }
3274
3275         redraw_mask |= REDRAW_DOOR_1;
3276         door_1_done = (a == end);
3277       }
3278
3279       if (door_state & DOOR_ACTION_2)
3280       {
3281         int a = MIN(x * door_2.step_offset, door_size);
3282         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3283         int i = p + door_skip;
3284
3285         if (door_2.anim_mode & ANIM_STATIC_PANEL)
3286         {
3287           BlitBitmap(bitmap_db_door, drawto,
3288                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3289                      VXSIZE, VYSIZE, VX, VY);
3290         }
3291         else if (x <= VYSIZE)
3292         {
3293           BlitBitmap(bitmap_db_door, drawto,
3294                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3295                      VXSIZE, VYSIZE - p / 2, VX, VY);
3296
3297           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3298         }
3299
3300         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3301         {
3302           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3303           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3304           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
3305           int dst2_x = VX,              dst2_y = VY;
3306           int width = i, height = VYSIZE;
3307
3308           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3309           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3310                            dst1_x, dst1_y);
3311
3312           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3313           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3314                            dst2_x, dst2_y);
3315         }
3316         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3317         {
3318           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3319           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
3320           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3321           int dst2_x = VX,              dst2_y = VY;
3322           int width = VXSIZE, height = i;
3323
3324           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3325           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3326                            dst1_x, dst1_y);
3327
3328           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3329           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3330                            dst2_x, dst2_y);
3331         }
3332         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
3333         {
3334           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3335
3336           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3337           BlitBitmapMasked(bitmap, drawto,
3338                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3339                            VX + VXSIZE - i, VY + j);
3340           SetClipOrigin(bitmap, gc,
3341                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3342           BlitBitmapMasked(bitmap, drawto,
3343                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3344                            VX, VY);
3345
3346           BlitBitmapMasked(bitmap, drawto,
3347                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3348                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3349           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3350           BlitBitmapMasked(bitmap, drawto,
3351                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3352                            i, VYSIZE / 2 - j,
3353                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3354         }
3355
3356         redraw_mask |= REDRAW_DOOR_2;
3357         door_2_done = (a == VXSIZE);
3358       }
3359
3360       if (!(door_state & DOOR_NO_DELAY))
3361       {
3362         BackToFront();
3363
3364         if (game_status == GAME_MODE_MAIN)
3365           DoAnimation();
3366
3367         WaitUntilDelayReached(&door_delay, door_delay_value);
3368       }
3369     }
3370   }
3371
3372   if (door_state & DOOR_ACTION_1)
3373     door1 = door_state & DOOR_ACTION_1;
3374   if (door_state & DOOR_ACTION_2)
3375     door2 = door_state & DOOR_ACTION_2;
3376
3377   return (door1 | door2);
3378 }
3379
3380 void DrawSpecialEditorDoor()
3381 {
3382   /* draw bigger toolbox window */
3383   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3384              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3385              EX - 4, EY - 12);
3386   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3387              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3388              EX - 6, EY - 4);
3389
3390   redraw_mask |= REDRAW_ALL;
3391 }
3392
3393 void UndrawSpecialEditorDoor()
3394 {
3395   /* draw normal tape recorder window */
3396   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3397              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3398              EX - 6, EY - 12);
3399
3400   redraw_mask |= REDRAW_ALL;
3401 }
3402
3403
3404 /* ---------- new tool button stuff ---------------------------------------- */
3405
3406 /* graphic position values for tool buttons */
3407 #define TOOL_BUTTON_YES_XPOS            2
3408 #define TOOL_BUTTON_YES_YPOS            250
3409 #define TOOL_BUTTON_YES_GFX_YPOS        0
3410 #define TOOL_BUTTON_YES_XSIZE           46
3411 #define TOOL_BUTTON_YES_YSIZE           28
3412 #define TOOL_BUTTON_NO_XPOS             52
3413 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
3414 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
3415 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
3416 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
3417 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
3418 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
3419 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
3420 #define TOOL_BUTTON_CONFIRM_XSIZE       96
3421 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
3422 #define TOOL_BUTTON_PLAYER_XSIZE        30
3423 #define TOOL_BUTTON_PLAYER_YSIZE        30
3424 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
3425 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3426 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3427 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3428 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3429                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3430 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3431                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3432 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3433                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3434 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3435                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3436 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3437                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3438 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3439                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3440 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3441                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3442 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3443                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3444
3445 static struct
3446 {
3447   int xpos, ypos;
3448   int x, y;
3449   int width, height;
3450   int gadget_id;
3451   char *infotext;
3452 } toolbutton_info[NUM_TOOL_BUTTONS] =
3453 {
3454   {
3455     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3456     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3457     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3458     TOOL_CTRL_ID_YES,
3459     "yes"
3460   },
3461   {
3462     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3463     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3464     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3465     TOOL_CTRL_ID_NO,
3466     "no"
3467   },
3468   {
3469     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3470     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3471     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3472     TOOL_CTRL_ID_CONFIRM,
3473     "confirm"
3474   },
3475   {
3476     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3477     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3478     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3479     TOOL_CTRL_ID_PLAYER_1,
3480     "player 1"
3481   },
3482   {
3483     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3484     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3485     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3486     TOOL_CTRL_ID_PLAYER_2,
3487     "player 2"
3488   },
3489   {
3490     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3491     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3492     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3493     TOOL_CTRL_ID_PLAYER_3,
3494     "player 3"
3495   },
3496   {
3497     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3498     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3499     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3500     TOOL_CTRL_ID_PLAYER_4,
3501     "player 4"
3502   }
3503 };
3504
3505 void CreateToolButtons()
3506 {
3507   int i;
3508
3509   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3510   {
3511     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3512     Bitmap *deco_bitmap = None;
3513     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3514     struct GadgetInfo *gi;
3515     unsigned long event_mask;
3516     int gd_xoffset, gd_yoffset;
3517     int gd_x1, gd_x2, gd_y;
3518     int id = i;
3519
3520     event_mask = GD_EVENT_RELEASED;
3521
3522     gd_xoffset = toolbutton_info[i].xpos;
3523     gd_yoffset = toolbutton_info[i].ypos;
3524     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3525     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3526     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3527
3528     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3529     {
3530       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3531
3532       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3533                            &deco_bitmap, &deco_x, &deco_y);
3534       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3535       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3536     }
3537
3538     gi = CreateGadget(GDI_CUSTOM_ID, id,
3539                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3540                       GDI_X, DX + toolbutton_info[i].x,
3541                       GDI_Y, DY + toolbutton_info[i].y,
3542                       GDI_WIDTH, toolbutton_info[i].width,
3543                       GDI_HEIGHT, toolbutton_info[i].height,
3544                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3545                       GDI_STATE, GD_BUTTON_UNPRESSED,
3546                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3547                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3548                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3549                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3550                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3551                       GDI_DECORATION_SHIFTING, 1, 1,
3552                       GDI_DIRECT_DRAW, FALSE,
3553                       GDI_EVENT_MASK, event_mask,
3554                       GDI_CALLBACK_ACTION, HandleToolButtons,
3555                       GDI_END);
3556
3557     if (gi == NULL)
3558       Error(ERR_EXIT, "cannot create gadget");
3559
3560     tool_gadget[id] = gi;
3561   }
3562 }
3563
3564 void FreeToolButtons()
3565 {
3566   int i;
3567
3568   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3569     FreeGadget(tool_gadget[i]);
3570 }
3571
3572 static void UnmapToolButtons()
3573 {
3574   int i;
3575
3576   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3577     UnmapGadget(tool_gadget[i]);
3578 }
3579
3580 static void HandleToolButtons(struct GadgetInfo *gi)
3581 {
3582   request_gadget_id = gi->custom_id;
3583 }
3584
3585 static struct Mapping_EM_to_RND_object
3586 {
3587   int element_em;
3588   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3589   boolean is_backside;                  /* backside of moving element */
3590
3591   int element_rnd;
3592   int action;
3593   int direction;
3594 }
3595 em_object_mapping_list[] =
3596 {
3597   {
3598     Xblank,                             TRUE,   FALSE,
3599     EL_EMPTY,                           -1, -1
3600   },
3601   {
3602     Yacid_splash_eB,                    FALSE,  FALSE,
3603     EL_ACID_SPLASH_RIGHT,               -1, -1
3604   },
3605   {
3606     Yacid_splash_wB,                    FALSE,  FALSE,
3607     EL_ACID_SPLASH_LEFT,                -1, -1
3608   },
3609
3610 #ifdef EM_ENGINE_BAD_ROLL
3611   {
3612     Xstone_force_e,                     FALSE,  FALSE,
3613     EL_ROCK,                            -1, MV_BIT_RIGHT
3614   },
3615   {
3616     Xstone_force_w,                     FALSE,  FALSE,
3617     EL_ROCK,                            -1, MV_BIT_LEFT
3618   },
3619   {
3620     Xnut_force_e,                       FALSE,  FALSE,
3621     EL_NUT,                             -1, MV_BIT_RIGHT
3622   },
3623   {
3624     Xnut_force_w,                       FALSE,  FALSE,
3625     EL_NUT,                             -1, MV_BIT_LEFT
3626   },
3627   {
3628     Xspring_force_e,                    FALSE,  FALSE,
3629     EL_SPRING,                          -1, MV_BIT_RIGHT
3630   },
3631   {
3632     Xspring_force_w,                    FALSE,  FALSE,
3633     EL_SPRING,                          -1, MV_BIT_LEFT
3634   },
3635   {
3636     Xemerald_force_e,                   FALSE,  FALSE,
3637     EL_EMERALD,                         -1, MV_BIT_RIGHT
3638   },
3639   {
3640     Xemerald_force_w,                   FALSE,  FALSE,
3641     EL_EMERALD,                         -1, MV_BIT_LEFT
3642   },
3643   {
3644     Xdiamond_force_e,                   FALSE,  FALSE,
3645     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3646   },
3647   {
3648     Xdiamond_force_w,                   FALSE,  FALSE,
3649     EL_DIAMOND,                         -1, MV_BIT_LEFT
3650   },
3651   {
3652     Xbomb_force_e,                      FALSE,  FALSE,
3653     EL_BOMB,                            -1, MV_BIT_RIGHT
3654   },
3655   {
3656     Xbomb_force_w,                      FALSE,  FALSE,
3657     EL_BOMB,                            -1, MV_BIT_LEFT
3658   },
3659 #endif  /* EM_ENGINE_BAD_ROLL */
3660
3661   {
3662     Xstone,                             TRUE,   FALSE,
3663     EL_ROCK,                            -1, -1
3664   },
3665   {
3666     Xstone_pause,                       FALSE,  FALSE,
3667     EL_ROCK,                            -1, -1
3668   },
3669   {
3670     Xstone_fall,                        FALSE,  FALSE,
3671     EL_ROCK,                            -1, -1
3672   },
3673   {
3674     Ystone_s,                           FALSE,  FALSE,
3675     EL_ROCK,                            ACTION_FALLING, -1
3676   },
3677   {
3678     Ystone_sB,                          FALSE,  TRUE,
3679     EL_ROCK,                            ACTION_FALLING, -1
3680   },
3681   {
3682     Ystone_e,                           FALSE,  FALSE,
3683     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3684   },
3685   {
3686     Ystone_eB,                          FALSE,  TRUE,
3687     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3688   },
3689   {
3690     Ystone_w,                           FALSE,  FALSE,
3691     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3692   },
3693   {
3694     Ystone_wB,                          FALSE,  TRUE,
3695     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3696   },
3697   {
3698     Xnut,                               TRUE,   FALSE,
3699     EL_NUT,                             -1, -1
3700   },
3701   {
3702     Xnut_pause,                         FALSE,  FALSE,
3703     EL_NUT,                             -1, -1
3704   },
3705   {
3706     Xnut_fall,                          FALSE,  FALSE,
3707     EL_NUT,                             -1, -1
3708   },
3709   {
3710     Ynut_s,                             FALSE,  FALSE,
3711     EL_NUT,                             ACTION_FALLING, -1
3712   },
3713   {
3714     Ynut_sB,                            FALSE,  TRUE,
3715     EL_NUT,                             ACTION_FALLING, -1
3716   },
3717   {
3718     Ynut_e,                             FALSE,  FALSE,
3719     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3720   },
3721   {
3722     Ynut_eB,                            FALSE,  TRUE,
3723     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3724   },
3725   {
3726     Ynut_w,                             FALSE,  FALSE,
3727     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3728   },
3729   {
3730     Ynut_wB,                            FALSE,  TRUE,
3731     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3732   },
3733   {
3734     Xbug_n,                             TRUE,   FALSE,
3735     EL_BUG_UP,                          -1, -1
3736   },
3737   {
3738     Xbug_e,                             TRUE,   FALSE,
3739     EL_BUG_RIGHT,                       -1, -1
3740   },
3741   {
3742     Xbug_s,                             TRUE,   FALSE,
3743     EL_BUG_DOWN,                        -1, -1
3744   },
3745   {
3746     Xbug_w,                             TRUE,   FALSE,
3747     EL_BUG_LEFT,                        -1, -1
3748   },
3749   {
3750     Xbug_gon,                           FALSE,  FALSE,
3751     EL_BUG_UP,                          -1, -1
3752   },
3753   {
3754     Xbug_goe,                           FALSE,  FALSE,
3755     EL_BUG_RIGHT,                       -1, -1
3756   },
3757   {
3758     Xbug_gos,                           FALSE,  FALSE,
3759     EL_BUG_DOWN,                        -1, -1
3760   },
3761   {
3762     Xbug_gow,                           FALSE,  FALSE,
3763     EL_BUG_LEFT,                        -1, -1
3764   },
3765   {
3766     Ybug_n,                             FALSE,  FALSE,
3767     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3768   },
3769   {
3770     Ybug_nB,                            FALSE,  TRUE,
3771     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3772   },
3773   {
3774     Ybug_e,                             FALSE,  FALSE,
3775     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3776   },
3777   {
3778     Ybug_eB,                            FALSE,  TRUE,
3779     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3780   },
3781   {
3782     Ybug_s,                             FALSE,  FALSE,
3783     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3784   },
3785   {
3786     Ybug_sB,                            FALSE,  TRUE,
3787     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3788   },
3789   {
3790     Ybug_w,                             FALSE,  FALSE,
3791     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3792   },
3793   {
3794     Ybug_wB,                            FALSE,  TRUE,
3795     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3796   },
3797   {
3798     Ybug_w_n,                           FALSE,  FALSE,
3799     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3800   },
3801   {
3802     Ybug_n_e,                           FALSE,  FALSE,
3803     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3804   },
3805   {
3806     Ybug_e_s,                           FALSE,  FALSE,
3807     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3808   },
3809   {
3810     Ybug_s_w,                           FALSE,  FALSE,
3811     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3812   },
3813   {
3814     Ybug_e_n,                           FALSE,  FALSE,
3815     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3816   },
3817   {
3818     Ybug_s_e,                           FALSE,  FALSE,
3819     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3820   },
3821   {
3822     Ybug_w_s,                           FALSE,  FALSE,
3823     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3824   },
3825   {
3826     Ybug_n_w,                           FALSE,  FALSE,
3827     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3828   },
3829   {
3830     Ybug_stone,                         FALSE,  FALSE,
3831     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3832   },
3833   {
3834     Ybug_spring,                        FALSE,  FALSE,
3835     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3836   },
3837   {
3838     Xtank_n,                            TRUE,   FALSE,
3839     EL_SPACESHIP_UP,                    -1, -1
3840   },
3841   {
3842     Xtank_e,                            TRUE,   FALSE,
3843     EL_SPACESHIP_RIGHT,                 -1, -1
3844   },
3845   {
3846     Xtank_s,                            TRUE,   FALSE,
3847     EL_SPACESHIP_DOWN,                  -1, -1
3848   },
3849   {
3850     Xtank_w,                            TRUE,   FALSE,
3851     EL_SPACESHIP_LEFT,                  -1, -1
3852   },
3853   {
3854     Xtank_gon,                          FALSE,  FALSE,
3855     EL_SPACESHIP_UP,                    -1, -1
3856   },
3857   {
3858     Xtank_goe,                          FALSE,  FALSE,
3859     EL_SPACESHIP_RIGHT,                 -1, -1
3860   },
3861   {
3862     Xtank_gos,                          FALSE,  FALSE,
3863     EL_SPACESHIP_DOWN,                  -1, -1
3864   },
3865   {
3866     Xtank_gow,                          FALSE,  FALSE,
3867     EL_SPACESHIP_LEFT,                  -1, -1
3868   },
3869   {
3870     Ytank_n,                            FALSE,  FALSE,
3871     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3872   },
3873   {
3874     Ytank_nB,                           FALSE,  TRUE,
3875     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3876   },
3877   {
3878     Ytank_e,                            FALSE,  FALSE,
3879     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3880   },
3881   {
3882     Ytank_eB,                           FALSE,  TRUE,
3883     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3884   },
3885   {
3886     Ytank_s,                            FALSE,  FALSE,
3887     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3888   },
3889   {
3890     Ytank_sB,                           FALSE,  TRUE,
3891     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3892   },
3893   {
3894     Ytank_w,                            FALSE,  FALSE,
3895     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3896   },
3897   {
3898     Ytank_wB,                           FALSE,  TRUE,
3899     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3900   },
3901   {
3902     Ytank_w_n,                          FALSE,  FALSE,
3903     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3904   },
3905   {
3906     Ytank_n_e,                          FALSE,  FALSE,
3907     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3908   },
3909   {
3910     Ytank_e_s,                          FALSE,  FALSE,
3911     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3912   },
3913   {
3914     Ytank_s_w,                          FALSE,  FALSE,
3915     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3916   },
3917   {
3918     Ytank_e_n,                          FALSE,  FALSE,
3919     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3920   },
3921   {
3922     Ytank_s_e,                          FALSE,  FALSE,
3923     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3924   },
3925   {
3926     Ytank_w_s,                          FALSE,  FALSE,
3927     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3928   },
3929   {
3930     Ytank_n_w,                          FALSE,  FALSE,
3931     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3932   },
3933   {
3934     Ytank_stone,                        FALSE,  FALSE,
3935     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3936   },
3937   {
3938     Ytank_spring,                       FALSE,  FALSE,
3939     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3940   },
3941   {
3942     Xandroid,                           TRUE,   FALSE,
3943     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3944   },
3945   {
3946     Xandroid_1_n,                       FALSE,  FALSE,
3947     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3948   },
3949   {
3950     Xandroid_2_n,                       FALSE,  FALSE,
3951     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3952   },
3953   {
3954     Xandroid_1_e,                       FALSE,  FALSE,
3955     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3956   },
3957   {
3958     Xandroid_2_e,                       FALSE,  FALSE,
3959     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3960   },
3961   {
3962     Xandroid_1_w,                       FALSE,  FALSE,
3963     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3964   },
3965   {
3966     Xandroid_2_w,                       FALSE,  FALSE,
3967     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3968   },
3969   {
3970     Xandroid_1_s,                       FALSE,  FALSE,
3971     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3972   },
3973   {
3974     Xandroid_2_s,                       FALSE,  FALSE,
3975     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3976   },
3977   {
3978     Yandroid_n,                         FALSE,  FALSE,
3979     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3980   },
3981   {
3982     Yandroid_nB,                        FALSE,  TRUE,
3983     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3984   },
3985   {
3986     Yandroid_ne,                        FALSE,  FALSE,
3987     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
3988   },
3989   {
3990     Yandroid_neB,                       FALSE,  TRUE,
3991     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
3992   },
3993   {
3994     Yandroid_e,                         FALSE,  FALSE,
3995     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3996   },
3997   {
3998     Yandroid_eB,                        FALSE,  TRUE,
3999     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4000   },
4001   {
4002     Yandroid_se,                        FALSE,  FALSE,
4003     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
4004   },
4005   {
4006     Yandroid_seB,                       FALSE,  TRUE,
4007     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4008   },
4009   {
4010     Yandroid_s,                         FALSE,  FALSE,
4011     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4012   },
4013   {
4014     Yandroid_sB,                        FALSE,  TRUE,
4015     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4016   },
4017   {
4018     Yandroid_sw,                        FALSE,  FALSE,
4019     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
4020   },
4021   {
4022     Yandroid_swB,                       FALSE,  TRUE,
4023     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
4024   },
4025   {
4026     Yandroid_w,                         FALSE,  FALSE,
4027     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4028   },
4029   {
4030     Yandroid_wB,                        FALSE,  TRUE,
4031     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4032   },
4033   {
4034     Yandroid_nw,                        FALSE,  FALSE,
4035     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
4036   },
4037   {
4038     Yandroid_nwB,                       FALSE,  TRUE,
4039     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
4040   },
4041   {
4042     Xspring,                            TRUE,   FALSE,
4043     EL_SPRING,                          -1, -1
4044   },
4045   {
4046     Xspring_pause,                      FALSE,  FALSE,
4047     EL_SPRING,                          -1, -1
4048   },
4049   {
4050     Xspring_e,                          FALSE,  FALSE,
4051     EL_SPRING,                          -1, -1
4052   },
4053   {
4054     Xspring_w,                          FALSE,  FALSE,
4055     EL_SPRING,                          -1, -1
4056   },
4057   {
4058     Xspring_fall,                       FALSE,  FALSE,
4059     EL_SPRING,                          -1, -1
4060   },
4061   {
4062     Yspring_s,                          FALSE,  FALSE,
4063     EL_SPRING,                          ACTION_FALLING, -1
4064   },
4065   {
4066     Yspring_sB,                         FALSE,  TRUE,
4067     EL_SPRING,                          ACTION_FALLING, -1
4068   },
4069   {
4070     Yspring_e,                          FALSE,  FALSE,
4071     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4072   },
4073   {
4074     Yspring_eB,                         FALSE,  TRUE,
4075     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4076   },
4077   {
4078     Yspring_w,                          FALSE,  FALSE,
4079     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4080   },
4081   {
4082     Yspring_wB,                         FALSE,  TRUE,
4083     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4084   },
4085   {
4086     Yspring_kill_e,                     FALSE,  FALSE,
4087     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4088   },
4089   {
4090     Yspring_kill_eB,                    FALSE,  TRUE,
4091     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4092   },
4093   {
4094     Yspring_kill_w,                     FALSE,  FALSE,
4095     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4096   },
4097   {
4098     Yspring_kill_wB,                    FALSE,  TRUE,
4099     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4100   },
4101   {
4102     Xeater_n,                           TRUE,   FALSE,
4103     EL_YAMYAM_UP,                       -1, -1
4104   },
4105   {
4106     Xeater_e,                           TRUE,   FALSE,
4107     EL_YAMYAM_RIGHT,                    -1, -1
4108   },
4109   {
4110     Xeater_w,                           TRUE,   FALSE,
4111     EL_YAMYAM_LEFT,                     -1, -1
4112   },
4113   {
4114     Xeater_s,                           TRUE,   FALSE,
4115     EL_YAMYAM_DOWN,                     -1, -1
4116   },
4117   {
4118     Yeater_n,                           FALSE,  FALSE,
4119     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4120   },
4121   {
4122     Yeater_nB,                          FALSE,  TRUE,
4123     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4124   },
4125   {
4126     Yeater_e,                           FALSE,  FALSE,
4127     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4128   },
4129   {
4130     Yeater_eB,                          FALSE,  TRUE,
4131     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4132   },
4133   {
4134     Yeater_s,                           FALSE,  FALSE,
4135     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4136   },
4137   {
4138     Yeater_sB,                          FALSE,  TRUE,
4139     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4140   },
4141   {
4142     Yeater_w,                           FALSE,  FALSE,
4143     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4144   },
4145   {
4146     Yeater_wB,                          FALSE,  TRUE,
4147     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4148   },
4149   {
4150     Yeater_stone,                       FALSE,  FALSE,
4151     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
4152   },
4153   {
4154     Yeater_spring,                      FALSE,  FALSE,
4155     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
4156   },
4157   {
4158     Xalien,                             TRUE,   FALSE,
4159     EL_ROBOT,                           -1, -1
4160   },
4161   {
4162     Xalien_pause,                       FALSE,  FALSE,
4163     EL_ROBOT,                           -1, -1
4164   },
4165   {
4166     Yalien_n,                           FALSE,  FALSE,
4167     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4168   },
4169   {
4170     Yalien_nB,                          FALSE,  TRUE,
4171     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4172   },
4173   {
4174     Yalien_e,                           FALSE,  FALSE,
4175     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4176   },
4177   {
4178     Yalien_eB,                          FALSE,  TRUE,
4179     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4180   },
4181   {
4182     Yalien_s,                           FALSE,  FALSE,
4183     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4184   },
4185   {
4186     Yalien_sB,                          FALSE,  TRUE,
4187     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4188   },
4189   {
4190     Yalien_w,                           FALSE,  FALSE,
4191     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4192   },
4193   {
4194     Yalien_wB,                          FALSE,  TRUE,
4195     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4196   },
4197   {
4198     Yalien_stone,                       FALSE,  FALSE,
4199     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
4200   },
4201   {
4202     Yalien_spring,                      FALSE,  FALSE,
4203     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
4204   },
4205   {
4206     Xemerald,                           TRUE,   FALSE,
4207     EL_EMERALD,                         -1, -1
4208   },
4209   {
4210     Xemerald_pause,                     FALSE,  FALSE,
4211     EL_EMERALD,                         -1, -1
4212   },
4213   {
4214     Xemerald_fall,                      FALSE,  FALSE,
4215     EL_EMERALD,                         -1, -1
4216   },
4217   {
4218     Xemerald_shine,                     FALSE,  FALSE,
4219     EL_EMERALD,                         ACTION_TWINKLING, -1
4220   },
4221   {
4222     Yemerald_s,                         FALSE,  FALSE,
4223     EL_EMERALD,                         ACTION_FALLING, -1
4224   },
4225   {
4226     Yemerald_sB,                        FALSE,  TRUE,
4227     EL_EMERALD,                         ACTION_FALLING, -1
4228   },
4229   {
4230     Yemerald_e,                         FALSE,  FALSE,
4231     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4232   },
4233   {
4234     Yemerald_eB,                        FALSE,  TRUE,
4235     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4236   },
4237   {
4238     Yemerald_w,                         FALSE,  FALSE,
4239     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4240   },
4241   {
4242     Yemerald_wB,                        FALSE,  TRUE,
4243     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4244   },
4245   {
4246     Yemerald_eat,                       FALSE,  FALSE,
4247     EL_EMERALD,                         ACTION_COLLECTING, -1
4248   },
4249   {
4250     Yemerald_stone,                     FALSE,  FALSE,
4251     EL_NUT,                             ACTION_BREAKING, -1
4252   },
4253   {
4254     Xdiamond,                           TRUE,   FALSE,
4255     EL_DIAMOND,                         -1, -1
4256   },
4257   {
4258     Xdiamond_pause,                     FALSE,  FALSE,
4259     EL_DIAMOND,                         -1, -1
4260   },
4261   {
4262     Xdiamond_fall,                      FALSE,  FALSE,
4263     EL_DIAMOND,                         -1, -1
4264   },
4265   {
4266     Xdiamond_shine,                     FALSE,  FALSE,
4267     EL_DIAMOND,                         ACTION_TWINKLING, -1
4268   },
4269   {
4270     Ydiamond_s,                         FALSE,  FALSE,
4271     EL_DIAMOND,                         ACTION_FALLING, -1
4272   },
4273   {
4274     Ydiamond_sB,                        FALSE,  TRUE,
4275     EL_DIAMOND,                         ACTION_FALLING, -1
4276   },
4277   {
4278     Ydiamond_e,                         FALSE,  FALSE,
4279     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4280   },
4281   {
4282     Ydiamond_eB,                        FALSE,  TRUE,
4283     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4284   },
4285   {
4286     Ydiamond_w,                         FALSE,  FALSE,
4287     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4288   },
4289   {
4290     Ydiamond_wB,                        FALSE,  TRUE,
4291     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4292   },
4293   {
4294     Ydiamond_eat,                       FALSE,  FALSE,
4295     EL_DIAMOND,                         ACTION_COLLECTING, -1
4296   },
4297   {
4298     Ydiamond_stone,                     FALSE,  FALSE,
4299     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
4300   },
4301   {
4302     Xdrip_fall,                         TRUE,   FALSE,
4303     EL_AMOEBA_DROP,                     -1, -1
4304   },
4305   {
4306     Xdrip_stretch,                      FALSE,  FALSE,
4307     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4308   },
4309   {
4310     Xdrip_stretchB,                     FALSE,  TRUE,
4311     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4312   },
4313   {
4314     Xdrip_eat,                          FALSE,  FALSE,
4315     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
4316   },
4317   {
4318     Ydrip_s1,                           FALSE,  FALSE,
4319     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4320   },
4321   {
4322     Ydrip_s1B,                          FALSE,  TRUE,
4323     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4324   },
4325   {
4326     Ydrip_s2,                           FALSE,  FALSE,
4327     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4328   },
4329   {
4330     Ydrip_s2B,                          FALSE,  TRUE,
4331     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4332   },
4333   {
4334     Xbomb,                              TRUE,   FALSE,
4335     EL_BOMB,                            -1, -1
4336   },
4337   {
4338     Xbomb_pause,                        FALSE,  FALSE,
4339     EL_BOMB,                            -1, -1
4340   },
4341   {
4342     Xbomb_fall,                         FALSE,  FALSE,
4343     EL_BOMB,                            -1, -1
4344   },
4345   {
4346     Ybomb_s,                            FALSE,  FALSE,
4347     EL_BOMB,                            ACTION_FALLING, -1
4348   },
4349   {
4350     Ybomb_sB,                           FALSE,  TRUE,
4351     EL_BOMB,                            ACTION_FALLING, -1
4352   },
4353   {
4354     Ybomb_e,                            FALSE,  FALSE,
4355     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4356   },
4357   {
4358     Ybomb_eB,                           FALSE,  TRUE,
4359     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4360   },
4361   {
4362     Ybomb_w,                            FALSE,  FALSE,
4363     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4364   },
4365   {
4366     Ybomb_wB,                           FALSE,  TRUE,
4367     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4368   },
4369   {
4370     Ybomb_eat,                          FALSE,  FALSE,
4371     EL_BOMB,                            ACTION_ACTIVATING, -1
4372   },
4373   {
4374     Xballoon,                           TRUE,   FALSE,
4375     EL_BALLOON,                         -1, -1
4376   },
4377   {
4378     Yballoon_n,                         FALSE,  FALSE,
4379     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4380   },
4381   {
4382     Yballoon_nB,                        FALSE,  TRUE,
4383     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4384   },
4385   {
4386     Yballoon_e,                         FALSE,  FALSE,
4387     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4388   },
4389   {
4390     Yballoon_eB,                        FALSE,  TRUE,
4391     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4392   },
4393   {
4394     Yballoon_s,                         FALSE,  FALSE,
4395     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4396   },
4397   {
4398     Yballoon_sB,                        FALSE,  TRUE,
4399     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4400   },
4401   {
4402     Yballoon_w,                         FALSE,  FALSE,
4403     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4404   },
4405   {
4406     Yballoon_wB,                        FALSE,  TRUE,
4407     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4408   },
4409   {
4410     Xgrass,                             TRUE,   FALSE,
4411     EL_EMC_GRASS,                       -1, -1
4412   },
4413   {
4414     Ygrass_nB,                          FALSE,  FALSE,
4415     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
4416   },
4417   {
4418     Ygrass_eB,                          FALSE,  FALSE,
4419     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
4420   },
4421   {
4422     Ygrass_sB,                          FALSE,  FALSE,
4423     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
4424   },
4425   {
4426     Ygrass_wB,                          FALSE,  FALSE,
4427     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4428   },
4429   {
4430     Xdirt,                              TRUE,   FALSE,
4431     EL_SAND,                            -1, -1
4432   },
4433   {
4434     Ydirt_nB,                           FALSE,  FALSE,
4435     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4436   },
4437   {
4438     Ydirt_eB,                           FALSE,  FALSE,
4439     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4440   },
4441   {
4442     Ydirt_sB,                           FALSE,  FALSE,
4443     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4444   },
4445   {
4446     Ydirt_wB,                           FALSE,  FALSE,
4447     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4448   },
4449   {
4450     Xacid_ne,                           TRUE,   FALSE,
4451     EL_ACID_POOL_TOPRIGHT,              -1, -1
4452   },
4453   {
4454     Xacid_se,                           TRUE,   FALSE,
4455     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4456   },
4457   {
4458     Xacid_s,                            TRUE,   FALSE,
4459     EL_ACID_POOL_BOTTOM,                -1, -1
4460   },
4461   {
4462     Xacid_sw,                           TRUE,   FALSE,
4463     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4464   },
4465   {
4466     Xacid_nw,                           TRUE,   FALSE,
4467     EL_ACID_POOL_TOPLEFT,               -1, -1
4468   },
4469   {
4470     Xacid_1,                            TRUE,   FALSE,
4471     EL_ACID,                            -1, -1
4472   },
4473   {
4474     Xacid_2,                            FALSE,  FALSE,
4475     EL_ACID,                            -1, -1
4476   },
4477   {
4478     Xacid_3,                            FALSE,  FALSE,
4479     EL_ACID,                            -1, -1
4480   },
4481   {
4482     Xacid_4,                            FALSE,  FALSE,
4483     EL_ACID,                            -1, -1
4484   },
4485   {
4486     Xacid_5,                            FALSE,  FALSE,
4487     EL_ACID,                            -1, -1
4488   },
4489   {
4490     Xacid_6,                            FALSE,  FALSE,
4491     EL_ACID,                            -1, -1
4492   },
4493   {
4494     Xacid_7,                            FALSE,  FALSE,
4495     EL_ACID,                            -1, -1
4496   },
4497   {
4498     Xacid_8,                            FALSE,  FALSE,
4499     EL_ACID,                            -1, -1
4500   },
4501   {
4502     Xball_1,                            TRUE,   FALSE,
4503     EL_EMC_MAGIC_BALL,                  -1, -1
4504   },
4505   {
4506     Xball_1B,                           FALSE,  FALSE,
4507     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4508   },
4509   {
4510     Xball_2,                            FALSE,  FALSE,
4511     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4512   },
4513   {
4514     Xball_2B,                           FALSE,  FALSE,
4515     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4516   },
4517   {
4518     Yball_eat,                          FALSE,  FALSE,
4519     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4520   },
4521   {
4522     Ykey_1_eat,                         FALSE,  FALSE,
4523     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4524   },
4525   {
4526     Ykey_2_eat,                         FALSE,  FALSE,
4527     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4528   },
4529   {
4530     Ykey_3_eat,                         FALSE,  FALSE,
4531     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4532   },
4533   {
4534     Ykey_4_eat,                         FALSE,  FALSE,
4535     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4536   },
4537   {
4538     Ykey_5_eat,                         FALSE,  FALSE,
4539     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4540   },
4541   {
4542     Ykey_6_eat,                         FALSE,  FALSE,
4543     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4544   },
4545   {
4546     Ykey_7_eat,                         FALSE,  FALSE,
4547     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4548   },
4549   {
4550     Ykey_8_eat,                         FALSE,  FALSE,
4551     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4552   },
4553   {
4554     Ylenses_eat,                        FALSE,  FALSE,
4555     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4556   },
4557   {
4558     Ymagnify_eat,                       FALSE,  FALSE,
4559     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4560   },
4561   {
4562     Ygrass_eat,                         FALSE,  FALSE,
4563     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4564   },
4565   {
4566     Ydirt_eat,                          FALSE,  FALSE,
4567     EL_SAND,                            ACTION_SNAPPING, -1
4568   },
4569   {
4570     Xgrow_ns,                           TRUE,   FALSE,
4571     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4572   },
4573   {
4574     Ygrow_ns_eat,                       FALSE,  FALSE,
4575     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4576   },
4577   {
4578     Xgrow_ew,                           TRUE,   FALSE,
4579     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4580   },
4581   {
4582     Ygrow_ew_eat,                       FALSE,  FALSE,
4583     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4584   },
4585   {
4586     Xwonderwall,                        TRUE,   FALSE,
4587     EL_MAGIC_WALL,                      -1, -1
4588   },
4589   {
4590     XwonderwallB,                       FALSE,  FALSE,
4591     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4592   },
4593   {
4594     Xamoeba_1,                          TRUE,   FALSE,
4595     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4596   },
4597   {
4598     Xamoeba_2,                          FALSE,  FALSE,
4599     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4600   },
4601   {
4602     Xamoeba_3,                          FALSE,  FALSE,
4603     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4604   },
4605   {
4606     Xamoeba_4,                          FALSE,  FALSE,
4607     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4608   },
4609   {
4610     Xamoeba_5,                          TRUE,   FALSE,
4611     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4612   },
4613   {
4614     Xamoeba_6,                          FALSE,  FALSE,
4615     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4616   },
4617   {
4618     Xamoeba_7,                          FALSE,  FALSE,
4619     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4620   },
4621   {
4622     Xamoeba_8,                          FALSE,  FALSE,
4623     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4624   },
4625   {
4626     Xdoor_1,                            TRUE,   FALSE,
4627     EL_EM_GATE_1,                       -1, -1
4628   },
4629   {
4630     Xdoor_2,                            TRUE,   FALSE,
4631     EL_EM_GATE_2,                       -1, -1
4632   },
4633   {
4634     Xdoor_3,                            TRUE,   FALSE,
4635     EL_EM_GATE_3,                       -1, -1
4636   },
4637   {
4638     Xdoor_4,                            TRUE,   FALSE,
4639     EL_EM_GATE_4,                       -1, -1
4640   },
4641   {
4642     Xdoor_5,                            TRUE,   FALSE,
4643     EL_EMC_GATE_5,                      -1, -1
4644   },
4645   {
4646     Xdoor_6,                            TRUE,   FALSE,
4647     EL_EMC_GATE_6,                      -1, -1
4648   },
4649   {
4650     Xdoor_7,                            TRUE,   FALSE,
4651     EL_EMC_GATE_7,                      -1, -1
4652   },
4653   {
4654     Xdoor_8,                            TRUE,   FALSE,
4655     EL_EMC_GATE_8,                      -1, -1
4656   },
4657   {
4658     Xkey_1,                             TRUE,   FALSE,
4659     EL_EM_KEY_1,                        -1, -1
4660   },
4661   {
4662     Xkey_2,                             TRUE,   FALSE,
4663     EL_EM_KEY_2,                        -1, -1
4664   },
4665   {
4666     Xkey_3,                             TRUE,   FALSE,
4667     EL_EM_KEY_3,                        -1, -1
4668   },
4669   {
4670     Xkey_4,                             TRUE,   FALSE,
4671     EL_EM_KEY_4,                        -1, -1
4672   },
4673   {
4674     Xkey_5,                             TRUE,   FALSE,
4675     EL_EMC_KEY_5,                       -1, -1
4676   },
4677   {
4678     Xkey_6,                             TRUE,   FALSE,
4679     EL_EMC_KEY_6,                       -1, -1
4680   },
4681   {
4682     Xkey_7,                             TRUE,   FALSE,
4683     EL_EMC_KEY_7,                       -1, -1
4684   },
4685   {
4686     Xkey_8,                             TRUE,   FALSE,
4687     EL_EMC_KEY_8,                       -1, -1
4688   },
4689   {
4690     Xwind_n,                            TRUE,   FALSE,
4691     EL_BALLOON_SWITCH_UP,               -1, -1
4692   },
4693   {
4694     Xwind_e,                            TRUE,   FALSE,
4695     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4696   },
4697   {
4698     Xwind_s,                            TRUE,   FALSE,
4699     EL_BALLOON_SWITCH_DOWN,             -1, -1
4700   },
4701   {
4702     Xwind_w,                            TRUE,   FALSE,
4703     EL_BALLOON_SWITCH_LEFT,             -1, -1
4704   },
4705   {
4706     Xwind_nesw,                         TRUE,   FALSE,
4707     EL_BALLOON_SWITCH_ANY,              -1, -1
4708   },
4709   {
4710     Xwind_stop,                         TRUE,   FALSE,
4711     EL_BALLOON_SWITCH_NONE,             -1, -1
4712   },
4713   {
4714     Xexit,                              TRUE,   FALSE,
4715     EL_EM_EXIT_CLOSED,                  -1, -1
4716   },
4717   {
4718     Xexit_1,                            TRUE,   FALSE,
4719     EL_EM_EXIT_OPEN,                    -1, -1
4720   },
4721   {
4722     Xexit_2,                            FALSE,  FALSE,
4723     EL_EM_EXIT_OPEN,                    -1, -1
4724   },
4725   {
4726     Xexit_3,                            FALSE,  FALSE,
4727     EL_EM_EXIT_OPEN,                    -1, -1
4728   },
4729   {
4730     Xdynamite,                          TRUE,   FALSE,
4731     EL_EM_DYNAMITE,                     -1, -1
4732   },
4733   {
4734     Ydynamite_eat,                      FALSE,  FALSE,
4735     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4736   },
4737   {
4738     Xdynamite_1,                        TRUE,   FALSE,
4739     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4740   },
4741   {
4742     Xdynamite_2,                        FALSE,  FALSE,
4743     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4744   },
4745   {
4746     Xdynamite_3,                        FALSE,  FALSE,
4747     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4748   },
4749   {
4750     Xdynamite_4,                        FALSE,  FALSE,
4751     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4752   },
4753   {
4754     Xbumper,                            TRUE,   FALSE,
4755     EL_EMC_SPRING_BUMPER,               -1, -1
4756   },
4757   {
4758     XbumperB,                           FALSE,  FALSE,
4759     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4760   },
4761   {
4762     Xwheel,                             TRUE,   FALSE,
4763     EL_ROBOT_WHEEL,                     -1, -1
4764   },
4765   {
4766     XwheelB,                            FALSE,  FALSE,
4767     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4768   },
4769   {
4770     Xswitch,                            TRUE,   FALSE,
4771     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4772   },
4773   {
4774     XswitchB,                           FALSE,  FALSE,
4775     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4776   },
4777   {
4778     Xsand,                              TRUE,   FALSE,
4779     EL_QUICKSAND_EMPTY,                 -1, -1
4780   },
4781   {
4782     Xsand_stone,                        TRUE,   FALSE,
4783     EL_QUICKSAND_FULL,                  -1, -1
4784   },
4785   {
4786     Xsand_stonein_1,                    FALSE,  TRUE,
4787     EL_ROCK,                            ACTION_FILLING, -1
4788   },
4789   {
4790     Xsand_stonein_2,                    FALSE,  TRUE,
4791     EL_ROCK,                            ACTION_FILLING, -1
4792   },
4793   {
4794     Xsand_stonein_3,                    FALSE,  TRUE,
4795     EL_ROCK,                            ACTION_FILLING, -1
4796   },
4797   {
4798     Xsand_stonein_4,                    FALSE,  TRUE,
4799     EL_ROCK,                            ACTION_FILLING, -1
4800   },
4801   {
4802     Xsand_stonesand_1,                  FALSE,  FALSE,
4803     EL_QUICKSAND_FULL,                  -1, -1
4804   },
4805   {
4806     Xsand_stonesand_2,                  FALSE,  FALSE,
4807     EL_QUICKSAND_FULL,                  -1, -1
4808   },
4809   {
4810     Xsand_stonesand_3,                  FALSE,  FALSE,
4811     EL_QUICKSAND_FULL,                  -1, -1
4812   },
4813   {
4814     Xsand_stonesand_4,                  FALSE,  FALSE,
4815     EL_QUICKSAND_FULL,                  -1, -1
4816   },
4817   {
4818     Xsand_stoneout_1,                   FALSE,  FALSE,
4819     EL_ROCK,                            ACTION_EMPTYING, -1
4820   },
4821   {
4822     Xsand_stoneout_2,                   FALSE,  FALSE,
4823     EL_ROCK,                            ACTION_EMPTYING, -1
4824   },
4825   {
4826     Xsand_sandstone_1,                  FALSE,  FALSE,
4827     EL_QUICKSAND_FULL,                  -1, -1
4828   },
4829   {
4830     Xsand_sandstone_2,                  FALSE,  FALSE,
4831     EL_QUICKSAND_FULL,                  -1, -1
4832   },
4833   {
4834     Xsand_sandstone_3,                  FALSE,  FALSE,
4835     EL_QUICKSAND_FULL,                  -1, -1
4836   },
4837   {
4838     Xsand_sandstone_4,                  FALSE,  FALSE,
4839     EL_QUICKSAND_FULL,                  -1, -1
4840   },
4841   {
4842     Xplant,                             TRUE,   FALSE,
4843     EL_EMC_PLANT,                       -1, -1
4844   },
4845   {
4846     Yplant,                             FALSE,  FALSE,
4847     EL_EMC_PLANT,                       -1, -1
4848   },
4849   {
4850     Xlenses,                            TRUE,   FALSE,
4851     EL_EMC_LENSES,                      -1, -1
4852   },
4853   {
4854     Xmagnify,                           TRUE,   FALSE,
4855     EL_EMC_MAGNIFIER,                   -1, -1
4856   },
4857   {
4858     Xdripper,                           TRUE,   FALSE,
4859     EL_EMC_DRIPPER,                     -1, -1
4860   },
4861   {
4862     XdripperB,                          FALSE,  FALSE,
4863     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4864   },
4865   {
4866     Xfake_blank,                        TRUE,   FALSE,
4867     EL_INVISIBLE_WALL,                  -1, -1
4868   },
4869   {
4870     Xfake_blankB,                       FALSE,  FALSE,
4871     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4872   },
4873   {
4874     Xfake_grass,                        TRUE,   FALSE,
4875     EL_EMC_FAKE_GRASS,                  -1, -1
4876   },
4877   {
4878     Xfake_grassB,                       FALSE,  FALSE,
4879     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4880   },
4881   {
4882     Xfake_door_1,                       TRUE,   FALSE,
4883     EL_EM_GATE_1_GRAY,                  -1, -1
4884   },
4885   {
4886     Xfake_door_2,                       TRUE,   FALSE,
4887     EL_EM_GATE_2_GRAY,                  -1, -1
4888   },
4889   {
4890     Xfake_door_3,                       TRUE,   FALSE,
4891     EL_EM_GATE_3_GRAY,                  -1, -1
4892   },
4893   {
4894     Xfake_door_4,                       TRUE,   FALSE,
4895     EL_EM_GATE_4_GRAY,                  -1, -1
4896   },
4897   {
4898     Xfake_door_5,                       TRUE,   FALSE,
4899     EL_EMC_GATE_5_GRAY,                 -1, -1
4900   },
4901   {
4902     Xfake_door_6,                       TRUE,   FALSE,
4903     EL_EMC_GATE_6_GRAY,                 -1, -1
4904   },
4905   {
4906     Xfake_door_7,                       TRUE,   FALSE,
4907     EL_EMC_GATE_7_GRAY,                 -1, -1
4908   },
4909   {
4910     Xfake_door_8,                       TRUE,   FALSE,
4911     EL_EMC_GATE_8_GRAY,                 -1, -1
4912   },
4913   {
4914     Xfake_acid_1,                       TRUE,   FALSE,
4915     EL_EMC_FAKE_ACID,                   -1, -1
4916   },
4917   {
4918     Xfake_acid_2,                       FALSE,  FALSE,
4919     EL_EMC_FAKE_ACID,                   -1, -1
4920   },
4921   {
4922     Xfake_acid_3,                       FALSE,  FALSE,
4923     EL_EMC_FAKE_ACID,                   -1, -1
4924   },
4925   {
4926     Xfake_acid_4,                       FALSE,  FALSE,
4927     EL_EMC_FAKE_ACID,                   -1, -1
4928   },
4929   {
4930     Xfake_acid_5,                       FALSE,  FALSE,
4931     EL_EMC_FAKE_ACID,                   -1, -1
4932   },
4933   {
4934     Xfake_acid_6,                       FALSE,  FALSE,
4935     EL_EMC_FAKE_ACID,                   -1, -1
4936   },
4937   {
4938     Xfake_acid_7,                       FALSE,  FALSE,
4939     EL_EMC_FAKE_ACID,                   -1, -1
4940   },
4941   {
4942     Xfake_acid_8,                       FALSE,  FALSE,
4943     EL_EMC_FAKE_ACID,                   -1, -1
4944   },
4945   {
4946     Xsteel_1,                           TRUE,   FALSE,
4947     EL_STEELWALL,                       -1, -1
4948   },
4949   {
4950     Xsteel_2,                           TRUE,   FALSE,
4951     EL_EMC_STEELWALL_2,                 -1, -1
4952   },
4953   {
4954     Xsteel_3,                           TRUE,   FALSE,
4955     EL_EMC_STEELWALL_3,                 -1, -1
4956   },
4957   {
4958     Xsteel_4,                           TRUE,   FALSE,
4959     EL_EMC_STEELWALL_4,                 -1, -1
4960   },
4961   {
4962     Xwall_1,                            TRUE,   FALSE,
4963     EL_WALL,                            -1, -1
4964   },
4965   {
4966     Xwall_2,                            TRUE,   FALSE,
4967     EL_EMC_WALL_14,                     -1, -1
4968   },
4969   {
4970     Xwall_3,                            TRUE,   FALSE,
4971     EL_EMC_WALL_15,                     -1, -1
4972   },
4973   {
4974     Xwall_4,                            TRUE,   FALSE,
4975     EL_EMC_WALL_16,                     -1, -1
4976   },
4977   {
4978     Xround_wall_1,                      TRUE,   FALSE,
4979     EL_WALL_SLIPPERY,                   -1, -1
4980   },
4981   {
4982     Xround_wall_2,                      TRUE,   FALSE,
4983     EL_EMC_WALL_SLIPPERY_2,             -1, -1
4984   },
4985   {
4986     Xround_wall_3,                      TRUE,   FALSE,
4987     EL_EMC_WALL_SLIPPERY_3,             -1, -1
4988   },
4989   {
4990     Xround_wall_4,                      TRUE,   FALSE,
4991     EL_EMC_WALL_SLIPPERY_4,             -1, -1
4992   },
4993   {
4994     Xdecor_1,                           TRUE,   FALSE,
4995     EL_EMC_WALL_8,                      -1, -1
4996   },
4997   {
4998     Xdecor_2,                           TRUE,   FALSE,
4999     EL_EMC_WALL_6,                      -1, -1
5000   },
5001   {
5002     Xdecor_3,                           TRUE,   FALSE,
5003     EL_EMC_WALL_4,                      -1, -1
5004   },
5005   {
5006     Xdecor_4,                           TRUE,   FALSE,
5007     EL_EMC_WALL_7,                      -1, -1
5008   },
5009   {
5010     Xdecor_5,                           TRUE,   FALSE,
5011     EL_EMC_WALL_5,                      -1, -1
5012   },
5013   {
5014     Xdecor_6,                           TRUE,   FALSE,
5015     EL_EMC_WALL_9,                      -1, -1
5016   },
5017   {
5018     Xdecor_7,                           TRUE,   FALSE,
5019     EL_EMC_WALL_10,                     -1, -1
5020   },
5021   {
5022     Xdecor_8,                           TRUE,   FALSE,
5023     EL_EMC_WALL_1,                      -1, -1
5024   },
5025   {
5026     Xdecor_9,                           TRUE,   FALSE,
5027     EL_EMC_WALL_2,                      -1, -1
5028   },
5029   {
5030     Xdecor_10,                          TRUE,   FALSE,
5031     EL_EMC_WALL_3,                      -1, -1
5032   },
5033   {
5034     Xdecor_11,                          TRUE,   FALSE,
5035     EL_EMC_WALL_11,                     -1, -1
5036   },
5037   {
5038     Xdecor_12,                          TRUE,   FALSE,
5039     EL_EMC_WALL_12,                     -1, -1
5040   },
5041   {
5042     Xalpha_0,                           TRUE,   FALSE,
5043     EL_CHAR('0'),                       -1, -1
5044   },
5045   {
5046     Xalpha_1,                           TRUE,   FALSE,
5047     EL_CHAR('1'),                       -1, -1
5048   },
5049   {
5050     Xalpha_2,                           TRUE,   FALSE,
5051     EL_CHAR('2'),                       -1, -1
5052   },
5053   {
5054     Xalpha_3,                           TRUE,   FALSE,
5055     EL_CHAR('3'),                       -1, -1
5056   },
5057   {
5058     Xalpha_4,                           TRUE,   FALSE,
5059     EL_CHAR('4'),                       -1, -1
5060   },
5061   {
5062     Xalpha_5,                           TRUE,   FALSE,
5063     EL_CHAR('5'),                       -1, -1
5064   },
5065   {
5066     Xalpha_6,                           TRUE,   FALSE,
5067     EL_CHAR('6'),                       -1, -1
5068   },
5069   {
5070     Xalpha_7,                           TRUE,   FALSE,
5071     EL_CHAR('7'),                       -1, -1
5072   },
5073   {
5074     Xalpha_8,                           TRUE,   FALSE,
5075     EL_CHAR('8'),                       -1, -1
5076   },
5077   {
5078     Xalpha_9,                           TRUE,   FALSE,
5079     EL_CHAR('9'),                       -1, -1
5080   },
5081   {
5082     Xalpha_excla,                       TRUE,   FALSE,
5083     EL_CHAR('!'),                       -1, -1
5084   },
5085   {
5086     Xalpha_quote,                       TRUE,   FALSE,
5087     EL_CHAR('"'),                       -1, -1
5088   },
5089   {
5090     Xalpha_comma,                       TRUE,   FALSE,
5091     EL_CHAR(','),                       -1, -1
5092   },
5093   {
5094     Xalpha_minus,                       TRUE,   FALSE,
5095     EL_CHAR('-'),                       -1, -1
5096   },
5097   {
5098     Xalpha_perio,                       TRUE,   FALSE,
5099     EL_CHAR('.'),                       -1, -1
5100   },
5101   {
5102     Xalpha_colon,                       TRUE,   FALSE,
5103     EL_CHAR(':'),                       -1, -1
5104   },
5105   {
5106     Xalpha_quest,                       TRUE,   FALSE,
5107     EL_CHAR('?'),                       -1, -1
5108   },
5109   {
5110     Xalpha_a,                           TRUE,   FALSE,
5111     EL_CHAR('A'),                       -1, -1
5112   },
5113   {
5114     Xalpha_b,                           TRUE,   FALSE,
5115     EL_CHAR('B'),                       -1, -1
5116   },
5117   {
5118     Xalpha_c,                           TRUE,   FALSE,
5119     EL_CHAR('C'),                       -1, -1
5120   },
5121   {
5122     Xalpha_d,                           TRUE,   FALSE,
5123     EL_CHAR('D'),                       -1, -1
5124   },
5125   {
5126     Xalpha_e,                           TRUE,   FALSE,
5127     EL_CHAR('E'),                       -1, -1
5128   },
5129   {
5130     Xalpha_f,                           TRUE,   FALSE,
5131     EL_CHAR('F'),                       -1, -1
5132   },
5133   {
5134     Xalpha_g,                           TRUE,   FALSE,
5135     EL_CHAR('G'),                       -1, -1
5136   },
5137   {
5138     Xalpha_h,                           TRUE,   FALSE,
5139     EL_CHAR('H'),                       -1, -1
5140   },
5141   {
5142     Xalpha_i,                           TRUE,   FALSE,
5143     EL_CHAR('I'),                       -1, -1
5144   },
5145   {
5146     Xalpha_j,                           TRUE,   FALSE,
5147     EL_CHAR('J'),                       -1, -1
5148   },
5149   {
5150     Xalpha_k,                           TRUE,   FALSE,
5151     EL_CHAR('K'),                       -1, -1
5152   },
5153   {
5154     Xalpha_l,                           TRUE,   FALSE,
5155     EL_CHAR('L'),                       -1, -1
5156   },
5157   {
5158     Xalpha_m,                           TRUE,   FALSE,
5159     EL_CHAR('M'),                       -1, -1
5160   },
5161   {
5162     Xalpha_n,                           TRUE,   FALSE,
5163     EL_CHAR('N'),                       -1, -1
5164   },
5165   {
5166     Xalpha_o,                           TRUE,   FALSE,
5167     EL_CHAR('O'),                       -1, -1
5168   },
5169   {
5170     Xalpha_p,                           TRUE,   FALSE,
5171     EL_CHAR('P'),                       -1, -1
5172   },
5173   {
5174     Xalpha_q,                           TRUE,   FALSE,
5175     EL_CHAR('Q'),                       -1, -1
5176   },
5177   {
5178     Xalpha_r,                           TRUE,   FALSE,
5179     EL_CHAR('R'),                       -1, -1
5180   },
5181   {
5182     Xalpha_s,                           TRUE,   FALSE,
5183     EL_CHAR('S'),                       -1, -1
5184   },
5185   {
5186     Xalpha_t,                           TRUE,   FALSE,
5187     EL_CHAR('T'),                       -1, -1
5188   },
5189   {
5190     Xalpha_u,                           TRUE,   FALSE,
5191     EL_CHAR('U'),                       -1, -1
5192   },
5193   {
5194     Xalpha_v,                           TRUE,   FALSE,
5195     EL_CHAR('V'),                       -1, -1
5196   },
5197   {
5198     Xalpha_w,                           TRUE,   FALSE,
5199     EL_CHAR('W'),                       -1, -1
5200   },
5201   {
5202     Xalpha_x,                           TRUE,   FALSE,
5203     EL_CHAR('X'),                       -1, -1
5204   },
5205   {
5206     Xalpha_y,                           TRUE,   FALSE,
5207     EL_CHAR('Y'),                       -1, -1
5208   },
5209   {
5210     Xalpha_z,                           TRUE,   FALSE,
5211     EL_CHAR('Z'),                       -1, -1
5212   },
5213   {
5214     Xalpha_arrow_e,                     TRUE,   FALSE,
5215     EL_CHAR('>'),                       -1, -1
5216   },
5217   {
5218     Xalpha_arrow_w,                     TRUE,   FALSE,
5219     EL_CHAR('<'),                       -1, -1
5220   },
5221   {
5222     Xalpha_copyr,                       TRUE,   FALSE,
5223     EL_CHAR('©'),                       -1, -1
5224   },
5225
5226   {
5227     Xboom_bug,                          FALSE,  FALSE,
5228     EL_BUG,                             ACTION_EXPLODING, -1
5229   },
5230   {
5231     Xboom_bomb,                         FALSE,  FALSE,
5232     EL_BOMB,                            ACTION_EXPLODING, -1
5233   },
5234   {
5235     Xboom_android,                      FALSE,  FALSE,
5236     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5237   },
5238   {
5239     Xboom_1,                            FALSE,  FALSE,
5240     EL_DEFAULT,                         ACTION_EXPLODING, -1
5241   },
5242   {
5243     Xboom_2,                            FALSE,  FALSE,
5244     EL_DEFAULT,                         ACTION_EXPLODING, -1
5245   },
5246   {
5247     Znormal,                            FALSE,  FALSE,
5248     EL_EMPTY,                           -1, -1
5249   },
5250   {
5251     Zdynamite,                          FALSE,  FALSE,
5252     EL_EMPTY,                           -1, -1
5253   },
5254   {
5255     Zplayer,                            FALSE,  FALSE,
5256     EL_EMPTY,                           -1, -1
5257   },
5258   {
5259     ZBORDER,                            FALSE,  FALSE,
5260     EL_EMPTY,                           -1, -1
5261   },
5262
5263   {
5264     -1,                                 FALSE,  FALSE,
5265     -1,                                 -1, -1
5266   }
5267 };
5268
5269 static struct Mapping_EM_to_RND_player
5270 {
5271   int action_em;
5272   int player_nr;
5273
5274   int element_rnd;
5275   int action;
5276   int direction;
5277 }
5278 em_player_mapping_list[] =
5279 {
5280   {
5281     SPR_walk + 0,                       0,
5282     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5283   },
5284   {
5285     SPR_walk + 1,                       0,
5286     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5287   },
5288   {
5289     SPR_walk + 2,                       0,
5290     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5291   },
5292   {
5293     SPR_walk + 3,                       0,
5294     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5295   },
5296   {
5297     SPR_push + 0,                       0,
5298     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5299   },
5300   {
5301     SPR_push + 1,                       0,
5302     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5303   },
5304   {
5305     SPR_push + 2,                       0,
5306     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5307   },
5308   {
5309     SPR_push + 3,                       0,
5310     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5311   },
5312   {
5313     SPR_spray + 0,                      0,
5314     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5315   },
5316   {
5317     SPR_spray + 1,                      0,
5318     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5319   },
5320   {
5321     SPR_spray + 2,                      0,
5322     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5323   },
5324   {
5325     SPR_spray + 3,                      0,
5326     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5327   },
5328   {
5329     SPR_walk + 0,                       1,
5330     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5331   },
5332   {
5333     SPR_walk + 1,                       1,
5334     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5335   },
5336   {
5337     SPR_walk + 2,                       1,
5338     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5339   },
5340   {
5341     SPR_walk + 3,                       1,
5342     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5343   },
5344   {
5345     SPR_push + 0,                       1,
5346     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5347   },
5348   {
5349     SPR_push + 1,                       1,
5350     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5351   },
5352   {
5353     SPR_push + 2,                       1,
5354     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5355   },
5356   {
5357     SPR_push + 3,                       1,
5358     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5359   },
5360   {
5361     SPR_spray + 0,                      1,
5362     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5363   },
5364   {
5365     SPR_spray + 1,                      1,
5366     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5367   },
5368   {
5369     SPR_spray + 2,                      1,
5370     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5371   },
5372   {
5373     SPR_spray + 3,                      1,
5374     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5375   },
5376   {
5377     SPR_still,                          0,
5378     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5379   },
5380   {
5381     SPR_still,                          1,
5382     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5383   },
5384   {
5385     SPR_walk + 0,                       2,
5386     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5387   },
5388   {
5389     SPR_walk + 1,                       2,
5390     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5391   },
5392   {
5393     SPR_walk + 2,                       2,
5394     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5395   },
5396   {
5397     SPR_walk + 3,                       2,
5398     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5399   },
5400   {
5401     SPR_push + 0,                       2,
5402     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5403   },
5404   {
5405     SPR_push + 1,                       2,
5406     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5407   },
5408   {
5409     SPR_push + 2,                       2,
5410     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5411   },
5412   {
5413     SPR_push + 3,                       2,
5414     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5415   },
5416   {
5417     SPR_spray + 0,                      2,
5418     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5419   },
5420   {
5421     SPR_spray + 1,                      2,
5422     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5423   },
5424   {
5425     SPR_spray + 2,                      2,
5426     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5427   },
5428   {
5429     SPR_spray + 3,                      2,
5430     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5431   },
5432   {
5433     SPR_walk + 0,                       3,
5434     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5435   },
5436   {
5437     SPR_walk + 1,                       3,
5438     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5439   },
5440   {
5441     SPR_walk + 2,                       3,
5442     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5443   },
5444   {
5445     SPR_walk + 3,                       3,
5446     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5447   },
5448   {
5449     SPR_push + 0,                       3,
5450     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5451   },
5452   {
5453     SPR_push + 1,                       3,
5454     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5455   },
5456   {
5457     SPR_push + 2,                       3,
5458     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5459   },
5460   {
5461     SPR_push + 3,                       3,
5462     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5463   },
5464   {
5465     SPR_spray + 0,                      3,
5466     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5467   },
5468   {
5469     SPR_spray + 1,                      3,
5470     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5471   },
5472   {
5473     SPR_spray + 2,                      3,
5474     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5475   },
5476   {
5477     SPR_spray + 3,                      3,
5478     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5479   },
5480   {
5481     SPR_still,                          2,
5482     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5483   },
5484   {
5485     SPR_still,                          3,
5486     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5487   },
5488
5489   {
5490     -1,                                 -1,
5491     -1,                                 -1, -1
5492   }
5493 };
5494
5495 int map_element_RND_to_EM(int element_rnd)
5496 {
5497   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5498   static boolean mapping_initialized = FALSE;
5499
5500   if (!mapping_initialized)
5501   {
5502     int i;
5503
5504     /* return "Xalpha_quest" for all undefined elements in mapping array */
5505     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5506       mapping_RND_to_EM[i] = Xalpha_quest;
5507
5508     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5509       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5510         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5511           em_object_mapping_list[i].element_em;
5512
5513     mapping_initialized = TRUE;
5514   }
5515
5516   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5517     return mapping_RND_to_EM[element_rnd];
5518
5519   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5520
5521   return EL_UNKNOWN;
5522 }
5523
5524 int map_element_EM_to_RND(int element_em)
5525 {
5526   static unsigned short mapping_EM_to_RND[TILE_MAX];
5527   static boolean mapping_initialized = FALSE;
5528
5529   if (!mapping_initialized)
5530   {
5531     int i;
5532
5533     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5534     for (i = 0; i < TILE_MAX; i++)
5535       mapping_EM_to_RND[i] = EL_UNKNOWN;
5536
5537     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5538       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5539         em_object_mapping_list[i].element_rnd;
5540
5541     mapping_initialized = TRUE;
5542   }
5543
5544   if (element_em >= 0 && element_em < TILE_MAX)
5545     return mapping_EM_to_RND[element_em];
5546
5547   Error(ERR_WARN, "invalid EM level element %d", element_em);
5548
5549   return EL_UNKNOWN;
5550 }
5551
5552 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5553 {
5554   struct LevelInfo_EM *level_em = level->native_em_level;
5555   struct LEVEL *lev = level_em->lev;
5556   int i, j;
5557
5558   for (i = 0; i < TILE_MAX; i++)
5559     lev->android_array[i] = Xblank;
5560
5561   for (i = 0; i < level->num_android_clone_elements; i++)
5562   {
5563     int element_rnd = level->android_clone_element[i];
5564     int element_em = map_element_RND_to_EM(element_rnd);
5565
5566     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5567       if (em_object_mapping_list[j].element_rnd == element_rnd)
5568         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5569   }
5570 }
5571
5572 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5573 {
5574   struct LevelInfo_EM *level_em = level->native_em_level;
5575   struct LEVEL *lev = level_em->lev;
5576   int i, j;
5577
5578   level->num_android_clone_elements = 0;
5579
5580   for (i = 0; i < TILE_MAX; i++)
5581   {
5582     int element_em = lev->android_array[i];
5583     int element_rnd;
5584     boolean element_found = FALSE;
5585
5586     if (element_em == Xblank)
5587       continue;
5588
5589     element_rnd = map_element_EM_to_RND(element_em);
5590
5591     for (j = 0; j < level->num_android_clone_elements; j++)
5592       if (level->android_clone_element[j] == element_rnd)
5593         element_found = TRUE;
5594
5595     if (!element_found)
5596     {
5597       level->android_clone_element[level->num_android_clone_elements++] =
5598         element_rnd;
5599
5600       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5601         break;
5602     }
5603   }
5604
5605   if (level->num_android_clone_elements == 0)
5606   {
5607     level->num_android_clone_elements = 1;
5608     level->android_clone_element[0] = EL_EMPTY;
5609   }
5610 }
5611
5612 int map_direction_RND_to_EM(int direction)
5613 {
5614   return (direction == MV_UP    ? 0 :
5615           direction == MV_RIGHT ? 1 :
5616           direction == MV_DOWN  ? 2 :
5617           direction == MV_LEFT  ? 3 :
5618           -1);
5619 }
5620
5621 int map_direction_EM_to_RND(int direction)
5622 {
5623   return (direction == 0 ? MV_UP    :
5624           direction == 1 ? MV_RIGHT :
5625           direction == 2 ? MV_DOWN  :
5626           direction == 3 ? MV_LEFT  :
5627           MV_NONE);
5628 }
5629
5630 int get_next_element(int element)
5631 {
5632   switch (element)
5633   {
5634     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5635     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5636     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5637     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5638     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5639     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5640     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5641     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5642     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5643     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5644     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5645
5646     default:                            return element;
5647   }
5648 }
5649
5650 #if 0
5651 int el_act_dir2img(int element, int action, int direction)
5652 {
5653   element = GFX_ELEMENT(element);
5654
5655   if (direction == MV_NONE)
5656     return element_info[element].graphic[action];
5657
5658   direction = MV_DIR_TO_BIT(direction);
5659
5660   return element_info[element].direction_graphic[action][direction];
5661 }
5662 #else
5663 int el_act_dir2img(int element, int action, int direction)
5664 {
5665   element = GFX_ELEMENT(element);
5666   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5667
5668   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5669   return element_info[element].direction_graphic[action][direction];
5670 }
5671 #endif
5672
5673 #if 0
5674 static int el_act_dir2crm(int element, int action, int direction)
5675 {
5676   element = GFX_ELEMENT(element);
5677
5678   if (direction == MV_NONE)
5679     return element_info[element].crumbled[action];
5680
5681   direction = MV_DIR_TO_BIT(direction);
5682
5683   return element_info[element].direction_crumbled[action][direction];
5684 }
5685 #else
5686 static int el_act_dir2crm(int element, int action, int direction)
5687 {
5688   element = GFX_ELEMENT(element);
5689   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5690
5691   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5692   return element_info[element].direction_crumbled[action][direction];
5693 }
5694 #endif
5695
5696 int el_act2img(int element, int action)
5697 {
5698   element = GFX_ELEMENT(element);
5699
5700   return element_info[element].graphic[action];
5701 }
5702
5703 int el_act2crm(int element, int action)
5704 {
5705   element = GFX_ELEMENT(element);
5706
5707   return element_info[element].crumbled[action];
5708 }
5709
5710 int el_dir2img(int element, int direction)
5711 {
5712   element = GFX_ELEMENT(element);
5713
5714   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5715 }
5716
5717 int el2baseimg(int element)
5718 {
5719   return element_info[element].graphic[ACTION_DEFAULT];
5720 }
5721
5722 int el2img(int element)
5723 {
5724   element = GFX_ELEMENT(element);
5725
5726   return element_info[element].graphic[ACTION_DEFAULT];
5727 }
5728
5729 int el2edimg(int element)
5730 {
5731   element = GFX_ELEMENT(element);
5732
5733   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5734 }
5735
5736 int el2preimg(int element)
5737 {
5738   element = GFX_ELEMENT(element);
5739
5740   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5741 }
5742
5743 int font2baseimg(int font_nr)
5744 {
5745   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5746 }
5747
5748 int getBeltNrFromBeltElement(int element)
5749 {
5750   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5751           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5752           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5753 }
5754
5755 int getBeltNrFromBeltActiveElement(int element)
5756 {
5757   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5758           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5759           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5760 }
5761
5762 int getBeltNrFromBeltSwitchElement(int element)
5763 {
5764   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5765           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5766           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5767 }
5768
5769 int getBeltDirNrFromBeltElement(int element)
5770 {
5771   static int belt_base_element[4] =
5772   {
5773     EL_CONVEYOR_BELT_1_LEFT,
5774     EL_CONVEYOR_BELT_2_LEFT,
5775     EL_CONVEYOR_BELT_3_LEFT,
5776     EL_CONVEYOR_BELT_4_LEFT
5777   };
5778
5779   int belt_nr = getBeltNrFromBeltElement(element);
5780   int belt_dir_nr = element - belt_base_element[belt_nr];
5781
5782   return (belt_dir_nr % 3);
5783 }
5784
5785 int getBeltDirNrFromBeltSwitchElement(int element)
5786 {
5787   static int belt_base_element[4] =
5788   {
5789     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5790     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5791     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5792     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5793   };
5794
5795   int belt_nr = getBeltNrFromBeltSwitchElement(element);
5796   int belt_dir_nr = element - belt_base_element[belt_nr];
5797
5798   return (belt_dir_nr % 3);
5799 }
5800
5801 int getBeltDirFromBeltElement(int element)
5802 {
5803   static int belt_move_dir[3] =
5804   {
5805     MV_LEFT,
5806     MV_NONE,
5807     MV_RIGHT
5808   };
5809
5810   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5811
5812   return belt_move_dir[belt_dir_nr];
5813 }
5814
5815 int getBeltDirFromBeltSwitchElement(int element)
5816 {
5817   static int belt_move_dir[3] =
5818   {
5819     MV_LEFT,
5820     MV_NONE,
5821     MV_RIGHT
5822   };
5823
5824   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5825
5826   return belt_move_dir[belt_dir_nr];
5827 }
5828
5829 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5830 {
5831   static int belt_base_element[4] =
5832   {
5833     EL_CONVEYOR_BELT_1_LEFT,
5834     EL_CONVEYOR_BELT_2_LEFT,
5835     EL_CONVEYOR_BELT_3_LEFT,
5836     EL_CONVEYOR_BELT_4_LEFT
5837   };
5838   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5839
5840   return belt_base_element[belt_nr] + belt_dir_nr;
5841 }
5842
5843 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5844 {
5845   static int belt_base_element[4] =
5846   {
5847     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5848     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5849     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5850     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5851   };
5852   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5853
5854   return belt_base_element[belt_nr] + belt_dir_nr;
5855 }
5856
5857 int getNumActivePlayers_EM()
5858 {
5859   int num_players = 0;
5860   int i;
5861
5862   if (!tape.playing)
5863     return -1;
5864
5865   for (i = 0; i < MAX_PLAYERS; i++)
5866     if (tape.player_participates[i])
5867       num_players++;
5868
5869   return num_players;
5870 }
5871
5872 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5873 {
5874   int game_frame_delay_value;
5875
5876   game_frame_delay_value =
5877     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5878      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5879      GameFrameDelay);
5880
5881   if (tape.playing && tape.warp_forward && !tape.pausing)
5882     game_frame_delay_value = 0;
5883
5884   return game_frame_delay_value;
5885 }
5886
5887 unsigned int InitRND(long seed)
5888 {
5889   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5890     return InitEngineRandom_EM(seed);
5891   else
5892     return InitEngineRandom_RND(seed);
5893 }
5894
5895 #if 1
5896 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5897 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5898 #endif
5899
5900 void ResetGfxAnimation_EM(int x, int y, int tile)
5901 {
5902   GfxFrame[x][y] = 0;
5903 }
5904
5905 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5906                                   Bitmap **src_bitmap, int *src_x, int *src_y,
5907                                   int x, int y)
5908 {
5909   int element         = object_mapping[tile].element_rnd;
5910   int action          = object_mapping[tile].action;
5911   int direction       = object_mapping[tile].direction;
5912   boolean is_backside = object_mapping[tile].is_backside;
5913   boolean action_removing = (action == ACTION_DIGGING ||
5914                              action == ACTION_SNAPPING ||
5915                              action == ACTION_COLLECTING);
5916   int effective_element = (frame_em > 0 ? element :
5917                            is_backside ? EL_EMPTY :
5918                            action_removing ? EL_EMPTY :
5919                            element);
5920   int graphic = (direction == MV_NONE ?
5921                  el_act2img(effective_element, action) :
5922                  el_act_dir2img(effective_element, action, direction));
5923   struct GraphicInfo *g = &graphic_info[graphic];
5924   int sync_frame;
5925
5926   if (graphic_info[graphic].anim_global_sync)
5927     sync_frame = FrameCounter;
5928   else
5929     sync_frame = 7 - frame_em;
5930
5931   SetRandomAnimationValue(x, y);
5932
5933   int frame = getAnimationFrame(g->anim_frames,
5934                                 g->anim_delay,
5935                                 g->anim_mode,
5936                                 g->anim_start_frame,
5937                                 sync_frame);
5938
5939   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5940 }
5941
5942 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5943                                   Bitmap **src_bitmap, int *src_x, int *src_y)
5944 {
5945   int element   = player_mapping[player_nr][anim].element_rnd;
5946   int action    = player_mapping[player_nr][anim].action;
5947   int direction = player_mapping[player_nr][anim].direction;
5948   int graphic = (direction == MV_NONE ?
5949                  el_act2img(element, action) :
5950                  el_act_dir2img(element, action, direction));
5951   struct GraphicInfo *g = &graphic_info[graphic];
5952   int sync_frame;
5953
5954   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5955
5956   stored_player[player_nr].StepFrame = 7 - frame_em;
5957
5958   sync_frame = stored_player[player_nr].Frame;
5959
5960 #if 0
5961   printf("::: %d: %d, %d [%d]\n",
5962          player_nr,
5963          stored_player[player_nr].Frame,
5964          stored_player[player_nr].StepFrame,
5965          FrameCounter);
5966 #endif
5967
5968   int frame = getAnimationFrame(g->anim_frames,
5969                                 g->anim_delay,
5970                                 g->anim_mode,
5971                                 g->anim_start_frame,
5972                                 sync_frame);
5973
5974   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5975 }
5976
5977 void InitGraphicInfo_EM(void)
5978 {
5979 #if 0
5980   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5981   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5982 #endif
5983   int i, j, p;
5984
5985 #if DEBUG_EM_GFX
5986   int num_em_gfx_errors = 0;
5987
5988   if (graphic_info_em_object[0][0].bitmap == NULL)
5989   {
5990     /* EM graphics not yet initialized in em_open_all() */
5991
5992     return;
5993   }
5994
5995   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5996 #endif
5997
5998   /* always start with reliable default values */
5999   for (i = 0; i < TILE_MAX; i++)
6000   {
6001     object_mapping[i].element_rnd = EL_UNKNOWN;
6002     object_mapping[i].is_backside = FALSE;
6003     object_mapping[i].action = ACTION_DEFAULT;
6004     object_mapping[i].direction = MV_NONE;
6005   }
6006
6007   /* always start with reliable default values */
6008   for (p = 0; p < MAX_PLAYERS; p++)
6009   {
6010     for (i = 0; i < SPR_MAX; i++)
6011     {
6012       player_mapping[p][i].element_rnd = EL_UNKNOWN;
6013       player_mapping[p][i].action = ACTION_DEFAULT;
6014       player_mapping[p][i].direction = MV_NONE;
6015     }
6016   }
6017
6018   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6019   {
6020     int e = em_object_mapping_list[i].element_em;
6021
6022     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6023     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6024
6025     if (em_object_mapping_list[i].action != -1)
6026       object_mapping[e].action = em_object_mapping_list[i].action;
6027
6028     if (em_object_mapping_list[i].direction != -1)
6029       object_mapping[e].direction =
6030         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6031   }
6032
6033   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6034   {
6035     int a = em_player_mapping_list[i].action_em;
6036     int p = em_player_mapping_list[i].player_nr;
6037
6038     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6039
6040     if (em_player_mapping_list[i].action != -1)
6041       player_mapping[p][a].action = em_player_mapping_list[i].action;
6042
6043     if (em_player_mapping_list[i].direction != -1)
6044       player_mapping[p][a].direction =
6045         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6046   }
6047
6048   for (i = 0; i < TILE_MAX; i++)
6049   {
6050     int element = object_mapping[i].element_rnd;
6051     int action = object_mapping[i].action;
6052     int direction = object_mapping[i].direction;
6053     boolean is_backside = object_mapping[i].is_backside;
6054     boolean action_removing = (action == ACTION_DIGGING ||
6055                                action == ACTION_SNAPPING ||
6056                                action == ACTION_COLLECTING);
6057     boolean action_exploding = ((action == ACTION_EXPLODING ||
6058                                  action == ACTION_SMASHED_BY_ROCK ||
6059                                  action == ACTION_SMASHED_BY_SPRING) &&
6060                                 element != EL_DIAMOND);
6061     boolean action_active = (action == ACTION_ACTIVE);
6062     boolean action_other = (action == ACTION_OTHER);
6063
6064     for (j = 0; j < 8; j++)
6065     {
6066       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6067                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6068                                j < 7 ? element :
6069                                i == Xdrip_stretch ? element :
6070                                i == Xdrip_stretchB ? element :
6071                                i == Ydrip_s1 ? element :
6072                                i == Ydrip_s1B ? element :
6073                                i == Xball_1B ? element :
6074                                i == Xball_2 ? element :
6075                                i == Xball_2B ? element :
6076                                i == Yball_eat ? element :
6077                                i == Ykey_1_eat ? element :
6078                                i == Ykey_2_eat ? element :
6079                                i == Ykey_3_eat ? element :
6080                                i == Ykey_4_eat ? element :
6081                                i == Ykey_5_eat ? element :
6082                                i == Ykey_6_eat ? element :
6083                                i == Ykey_7_eat ? element :
6084                                i == Ykey_8_eat ? element :
6085                                i == Ylenses_eat ? element :
6086                                i == Ymagnify_eat ? element :
6087                                i == Ygrass_eat ? element :
6088                                i == Ydirt_eat ? element :
6089                                i == Yemerald_stone ? EL_EMERALD :
6090                                i == Ydiamond_stone ? EL_ROCK :
6091                                i == Xsand_stonein_1 ? element :
6092                                i == Xsand_stonein_2 ? element :
6093                                i == Xsand_stonein_3 ? element :
6094                                i == Xsand_stonein_4 ? element :
6095                                is_backside ? EL_EMPTY :
6096                                action_removing ? EL_EMPTY :
6097                                element);
6098       int effective_action = (j < 7 ? action :
6099                               i == Xdrip_stretch ? action :
6100                               i == Xdrip_stretchB ? action :
6101                               i == Ydrip_s1 ? action :
6102                               i == Ydrip_s1B ? action :
6103                               i == Xball_1B ? action :
6104                               i == Xball_2 ? action :
6105                               i == Xball_2B ? action :
6106                               i == Yball_eat ? action :
6107                               i == Ykey_1_eat ? action :
6108                               i == Ykey_2_eat ? action :
6109                               i == Ykey_3_eat ? action :
6110                               i == Ykey_4_eat ? action :
6111                               i == Ykey_5_eat ? action :
6112                               i == Ykey_6_eat ? action :
6113                               i == Ykey_7_eat ? action :
6114                               i == Ykey_8_eat ? action :
6115                               i == Ylenses_eat ? action :
6116                               i == Ymagnify_eat ? action :
6117                               i == Ygrass_eat ? action :
6118                               i == Ydirt_eat ? action :
6119                               i == Xsand_stonein_1 ? action :
6120                               i == Xsand_stonein_2 ? action :
6121                               i == Xsand_stonein_3 ? action :
6122                               i == Xsand_stonein_4 ? action :
6123                               i == Xsand_stoneout_1 ? action :
6124                               i == Xsand_stoneout_2 ? action :
6125                               i == Xboom_android ? ACTION_EXPLODING :
6126                               action_exploding ? ACTION_EXPLODING :
6127                               action_active ? action :
6128                               action_other ? action :
6129                               ACTION_DEFAULT);
6130       int graphic = (el_act_dir2img(effective_element, effective_action,
6131                                     direction));
6132       int crumbled = (el_act_dir2crm(effective_element, effective_action,
6133                                      direction));
6134       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6135       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6136       boolean has_action_graphics = (graphic != base_graphic);
6137       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6138       struct GraphicInfo *g = &graphic_info[graphic];
6139       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6140       Bitmap *src_bitmap;
6141       int src_x, src_y;
6142       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6143       boolean special_animation = (action != ACTION_DEFAULT &&
6144                                    g->anim_frames == 3 &&
6145                                    g->anim_delay == 2 &&
6146                                    g->anim_mode & ANIM_LINEAR);
6147       int sync_frame = (i == Xdrip_stretch ? 7 :
6148                         i == Xdrip_stretchB ? 7 :
6149                         i == Ydrip_s2 ? j + 8 :
6150                         i == Ydrip_s2B ? j + 8 :
6151                         i == Xacid_1 ? 0 :
6152                         i == Xacid_2 ? 10 :
6153                         i == Xacid_3 ? 20 :
6154                         i == Xacid_4 ? 30 :
6155                         i == Xacid_5 ? 40 :
6156                         i == Xacid_6 ? 50 :
6157                         i == Xacid_7 ? 60 :
6158                         i == Xacid_8 ? 70 :
6159                         i == Xfake_acid_1 ? 0 :
6160                         i == Xfake_acid_2 ? 10 :
6161                         i == Xfake_acid_3 ? 20 :
6162                         i == Xfake_acid_4 ? 30 :
6163                         i == Xfake_acid_5 ? 40 :
6164                         i == Xfake_acid_6 ? 50 :
6165                         i == Xfake_acid_7 ? 60 :
6166                         i == Xfake_acid_8 ? 70 :
6167                         i == Xball_2 ? 7 :
6168                         i == Xball_2B ? j + 8 :
6169                         i == Yball_eat ? j + 1 :
6170                         i == Ykey_1_eat ? j + 1 :
6171                         i == Ykey_2_eat ? j + 1 :
6172                         i == Ykey_3_eat ? j + 1 :
6173                         i == Ykey_4_eat ? j + 1 :
6174                         i == Ykey_5_eat ? j + 1 :
6175                         i == Ykey_6_eat ? j + 1 :
6176                         i == Ykey_7_eat ? j + 1 :
6177                         i == Ykey_8_eat ? j + 1 :
6178                         i == Ylenses_eat ? j + 1 :
6179                         i == Ymagnify_eat ? j + 1 :
6180                         i == Ygrass_eat ? j + 1 :
6181                         i == Ydirt_eat ? j + 1 :
6182                         i == Xamoeba_1 ? 0 :
6183                         i == Xamoeba_2 ? 1 :
6184                         i == Xamoeba_3 ? 2 :
6185                         i == Xamoeba_4 ? 3 :
6186                         i == Xamoeba_5 ? 0 :
6187                         i == Xamoeba_6 ? 1 :
6188                         i == Xamoeba_7 ? 2 :
6189                         i == Xamoeba_8 ? 3 :
6190                         i == Xexit_2 ? j + 8 :
6191                         i == Xexit_3 ? j + 16 :
6192                         i == Xdynamite_1 ? 0 :
6193                         i == Xdynamite_2 ? 8 :
6194                         i == Xdynamite_3 ? 16 :
6195                         i == Xdynamite_4 ? 24 :
6196                         i == Xsand_stonein_1 ? j + 1 :
6197                         i == Xsand_stonein_2 ? j + 9 :
6198                         i == Xsand_stonein_3 ? j + 17 :
6199                         i == Xsand_stonein_4 ? j + 25 :
6200                         i == Xsand_stoneout_1 && j == 0 ? 0 :
6201                         i == Xsand_stoneout_1 && j == 1 ? 0 :
6202                         i == Xsand_stoneout_1 && j == 2 ? 1 :
6203                         i == Xsand_stoneout_1 && j == 3 ? 2 :
6204                         i == Xsand_stoneout_1 && j == 4 ? 2 :
6205                         i == Xsand_stoneout_1 && j == 5 ? 3 :
6206                         i == Xsand_stoneout_1 && j == 6 ? 4 :
6207                         i == Xsand_stoneout_1 && j == 7 ? 4 :
6208                         i == Xsand_stoneout_2 && j == 0 ? 5 :
6209                         i == Xsand_stoneout_2 && j == 1 ? 6 :
6210                         i == Xsand_stoneout_2 && j == 2 ? 7 :
6211                         i == Xsand_stoneout_2 && j == 3 ? 8 :
6212                         i == Xsand_stoneout_2 && j == 4 ? 9 :
6213                         i == Xsand_stoneout_2 && j == 5 ? 11 :
6214                         i == Xsand_stoneout_2 && j == 6 ? 13 :
6215                         i == Xsand_stoneout_2 && j == 7 ? 15 :
6216                         i == Xboom_bug && j == 1 ? 2 :
6217                         i == Xboom_bug && j == 2 ? 2 :
6218                         i == Xboom_bug && j == 3 ? 4 :
6219                         i == Xboom_bug && j == 4 ? 4 :
6220                         i == Xboom_bug && j == 5 ? 2 :
6221                         i == Xboom_bug && j == 6 ? 2 :
6222                         i == Xboom_bug && j == 7 ? 0 :
6223                         i == Xboom_bomb && j == 1 ? 2 :
6224                         i == Xboom_bomb && j == 2 ? 2 :
6225                         i == Xboom_bomb && j == 3 ? 4 :
6226                         i == Xboom_bomb && j == 4 ? 4 :
6227                         i == Xboom_bomb && j == 5 ? 2 :
6228                         i == Xboom_bomb && j == 6 ? 2 :
6229                         i == Xboom_bomb && j == 7 ? 0 :
6230                         i == Xboom_android && j == 7 ? 6 :
6231                         i == Xboom_1 && j == 1 ? 2 :
6232                         i == Xboom_1 && j == 2 ? 2 :
6233                         i == Xboom_1 && j == 3 ? 4 :
6234                         i == Xboom_1 && j == 4 ? 4 :
6235                         i == Xboom_1 && j == 5 ? 6 :
6236                         i == Xboom_1 && j == 6 ? 6 :
6237                         i == Xboom_1 && j == 7 ? 8 :
6238                         i == Xboom_2 && j == 0 ? 8 :
6239                         i == Xboom_2 && j == 1 ? 8 :
6240                         i == Xboom_2 && j == 2 ? 10 :
6241                         i == Xboom_2 && j == 3 ? 10 :
6242                         i == Xboom_2 && j == 4 ? 10 :
6243                         i == Xboom_2 && j == 5 ? 12 :
6244                         i == Xboom_2 && j == 6 ? 12 :
6245                         i == Xboom_2 && j == 7 ? 12 :
6246                         special_animation && j == 4 ? 3 :
6247                         effective_action != action ? 0 :
6248                         j);
6249
6250 #if DEBUG_EM_GFX
6251       Bitmap *debug_bitmap = g_em->bitmap;
6252       int debug_src_x = g_em->src_x;
6253       int debug_src_y = g_em->src_y;
6254 #endif
6255
6256       int frame = getAnimationFrame(g->anim_frames,
6257                                     g->anim_delay,
6258                                     g->anim_mode,
6259                                     g->anim_start_frame,
6260                                     sync_frame);
6261
6262       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6263                           g->double_movement && is_backside);
6264
6265       g_em->bitmap = src_bitmap;
6266       g_em->src_x = src_x;
6267       g_em->src_y = src_y;
6268       g_em->src_offset_x = 0;
6269       g_em->src_offset_y = 0;
6270       g_em->dst_offset_x = 0;
6271       g_em->dst_offset_y = 0;
6272       g_em->width  = TILEX;
6273       g_em->height = TILEY;
6274
6275       g_em->crumbled_bitmap = NULL;
6276       g_em->crumbled_src_x = 0;
6277       g_em->crumbled_src_y = 0;
6278       g_em->crumbled_border_size = 0;
6279
6280       g_em->has_crumbled_graphics = FALSE;
6281       g_em->preserve_background = FALSE;
6282
6283 #if 0
6284       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6285         printf("::: empty crumbled: %d [%s], %d, %d\n",
6286                effective_element, element_info[effective_element].token_name,
6287                effective_action, direction);
6288 #endif
6289
6290       /* if element can be crumbled, but certain action graphics are just empty
6291          space (like snapping sand with the original R'n'D graphics), do not
6292          treat these empty space graphics as crumbled graphics in EMC engine */
6293       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6294       {
6295         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6296
6297         g_em->has_crumbled_graphics = TRUE;
6298         g_em->crumbled_bitmap = src_bitmap;
6299         g_em->crumbled_src_x = src_x;
6300         g_em->crumbled_src_y = src_y;
6301         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6302       }
6303
6304 #if 0
6305       if (element == EL_ROCK &&
6306           effective_action == ACTION_FILLING)
6307         printf("::: has_action_graphics == %d\n", has_action_graphics);
6308 #endif
6309
6310       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6311                                    effective_action == ACTION_MOVING  ||
6312                                    effective_action == ACTION_PUSHING ||
6313                                    effective_action == ACTION_EATING)) ||
6314           (!has_action_graphics && (effective_action == ACTION_FILLING ||
6315                                     effective_action == ACTION_EMPTYING)))
6316       {
6317         int move_dir =
6318           (effective_action == ACTION_FALLING ||
6319            effective_action == ACTION_FILLING ||
6320            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6321         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6322         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
6323         int num_steps = (i == Ydrip_s1  ? 16 :
6324                          i == Ydrip_s1B ? 16 :
6325                          i == Ydrip_s2  ? 16 :
6326                          i == Ydrip_s2B ? 16 :
6327                          i == Xsand_stonein_1 ? 32 :
6328                          i == Xsand_stonein_2 ? 32 :
6329                          i == Xsand_stonein_3 ? 32 :
6330                          i == Xsand_stonein_4 ? 32 :
6331                          i == Xsand_stoneout_1 ? 16 :
6332                          i == Xsand_stoneout_2 ? 16 : 8);
6333         int cx = ABS(dx) * (TILEX / num_steps);
6334         int cy = ABS(dy) * (TILEY / num_steps);
6335         int step_frame = (i == Ydrip_s2         ? j + 8 :
6336                           i == Ydrip_s2B        ? j + 8 :
6337                           i == Xsand_stonein_2  ? j + 8 :
6338                           i == Xsand_stonein_3  ? j + 16 :
6339                           i == Xsand_stonein_4  ? j + 24 :
6340                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6341         int step = (is_backside ? step_frame : num_steps - step_frame);
6342
6343         if (is_backside)        /* tile where movement starts */
6344         {
6345           if (dx < 0 || dy < 0)
6346           {
6347             g_em->src_offset_x = cx * step;
6348             g_em->src_offset_y = cy * step;
6349           }
6350           else
6351           {
6352             g_em->dst_offset_x = cx * step;
6353             g_em->dst_offset_y = cy * step;
6354           }
6355         }
6356         else                    /* tile where movement ends */
6357         {
6358           if (dx < 0 || dy < 0)
6359           {
6360             g_em->dst_offset_x = cx * step;
6361             g_em->dst_offset_y = cy * step;
6362           }
6363           else
6364           {
6365             g_em->src_offset_x = cx * step;
6366             g_em->src_offset_y = cy * step;
6367           }
6368         }
6369
6370         g_em->width  = TILEX - cx * step;
6371         g_em->height = TILEY - cy * step;
6372       }
6373
6374       /* create unique graphic identifier to decide if tile must be redrawn */
6375       /* bit 31 - 16 (16 bit): EM style graphic
6376          bit 15 - 12 ( 4 bit): EM style frame
6377          bit 11 -  6 ( 6 bit): graphic width
6378          bit  5 -  0 ( 6 bit): graphic height */
6379       g_em->unique_identifier =
6380         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6381
6382 #if DEBUG_EM_GFX
6383
6384       /* skip check for EMC elements not contained in original EMC artwork */
6385       if (element == EL_EMC_FAKE_ACID)
6386         continue;
6387
6388       if (g_em->bitmap != debug_bitmap ||
6389           g_em->src_x != debug_src_x ||
6390           g_em->src_y != debug_src_y ||
6391           g_em->src_offset_x != 0 ||
6392           g_em->src_offset_y != 0 ||
6393           g_em->dst_offset_x != 0 ||
6394           g_em->dst_offset_y != 0 ||
6395           g_em->width != TILEX ||
6396           g_em->height != TILEY)
6397       {
6398         static int last_i = -1;
6399
6400         if (i != last_i)
6401         {
6402           printf("\n");
6403           last_i = i;
6404         }
6405
6406         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6407                i, element, element_info[element].token_name,
6408                element_action_info[effective_action].suffix, direction);
6409
6410         if (element != effective_element)
6411           printf(" [%d ('%s')]",
6412                  effective_element,
6413                  element_info[effective_element].token_name);
6414
6415         printf("\n");
6416
6417         if (g_em->bitmap != debug_bitmap)
6418           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6419                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6420
6421         if (g_em->src_x != debug_src_x ||
6422             g_em->src_y != debug_src_y)
6423           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6424                  j, (is_backside ? 'B' : 'F'),
6425                  g_em->src_x, g_em->src_y,
6426                  g_em->src_x / 32, g_em->src_y / 32,
6427                  debug_src_x, debug_src_y,
6428                  debug_src_x / 32, debug_src_y / 32);
6429
6430         if (g_em->src_offset_x != 0 ||
6431             g_em->src_offset_y != 0 ||
6432             g_em->dst_offset_x != 0 ||
6433             g_em->dst_offset_y != 0)
6434           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6435                  j, is_backside,
6436                  g_em->src_offset_x, g_em->src_offset_y,
6437                  g_em->dst_offset_x, g_em->dst_offset_y);
6438
6439         if (g_em->width != TILEX ||
6440             g_em->height != TILEY)
6441           printf("    %d (%d): size %d,%d should be %d,%d\n",
6442                  j, is_backside,
6443                  g_em->width, g_em->height, TILEX, TILEY);
6444
6445         num_em_gfx_errors++;
6446       }
6447 #endif
6448
6449     }
6450   }
6451
6452   for (i = 0; i < TILE_MAX; i++)
6453   {
6454     for (j = 0; j < 8; j++)
6455     {
6456       int element = object_mapping[i].element_rnd;
6457       int action = object_mapping[i].action;
6458       int direction = object_mapping[i].direction;
6459       boolean is_backside = object_mapping[i].is_backside;
6460       int graphic_action  = el_act_dir2img(element, action, direction);
6461       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6462
6463       if ((action == ACTION_SMASHED_BY_ROCK ||
6464            action == ACTION_SMASHED_BY_SPRING ||
6465            action == ACTION_EATING) &&
6466           graphic_action == graphic_default)
6467       {
6468         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6469                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6470                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6471                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6472                  Xspring);
6473
6474         /* no separate animation for "smashed by rock" -- use rock instead */
6475         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6476         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6477
6478         g_em->bitmap            = g_xx->bitmap;
6479         g_em->src_x             = g_xx->src_x;
6480         g_em->src_y             = g_xx->src_y;
6481         g_em->src_offset_x      = g_xx->src_offset_x;
6482         g_em->src_offset_y      = g_xx->src_offset_y;
6483         g_em->dst_offset_x      = g_xx->dst_offset_x;
6484         g_em->dst_offset_y      = g_xx->dst_offset_y;
6485         g_em->width             = g_xx->width;
6486         g_em->height            = g_xx->height;
6487         g_em->unique_identifier = g_xx->unique_identifier;
6488
6489         if (!is_backside)
6490           g_em->preserve_background = TRUE;
6491       }
6492     }
6493   }
6494
6495   for (p = 0; p < MAX_PLAYERS; p++)
6496   {
6497     for (i = 0; i < SPR_MAX; i++)
6498     {
6499       int element = player_mapping[p][i].element_rnd;
6500       int action = player_mapping[p][i].action;
6501       int direction = player_mapping[p][i].direction;
6502
6503       for (j = 0; j < 8; j++)
6504       {
6505         int effective_element = element;
6506         int effective_action = action;
6507         int graphic = (direction == MV_NONE ?
6508                        el_act2img(effective_element, effective_action) :
6509                        el_act_dir2img(effective_element, effective_action,
6510                                       direction));
6511         struct GraphicInfo *g = &graphic_info[graphic];
6512         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6513         Bitmap *src_bitmap;
6514         int src_x, src_y;
6515         int sync_frame = j;
6516
6517 #if DEBUG_EM_GFX
6518         Bitmap *debug_bitmap = g_em->bitmap;
6519         int debug_src_x = g_em->src_x;
6520         int debug_src_y = g_em->src_y;
6521 #endif
6522
6523         int frame = getAnimationFrame(g->anim_frames,
6524                                       g->anim_delay,
6525                                       g->anim_mode,
6526                                       g->anim_start_frame,
6527                                       sync_frame);
6528
6529         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6530
6531         g_em->bitmap = src_bitmap;
6532         g_em->src_x = src_x;
6533         g_em->src_y = src_y;
6534         g_em->src_offset_x = 0;
6535         g_em->src_offset_y = 0;
6536         g_em->dst_offset_x = 0;
6537         g_em->dst_offset_y = 0;
6538         g_em->width  = TILEX;
6539         g_em->height = TILEY;
6540
6541 #if DEBUG_EM_GFX
6542
6543         /* skip check for EMC elements not contained in original EMC artwork */
6544         if (element == EL_PLAYER_3 ||
6545             element == EL_PLAYER_4)
6546           continue;
6547
6548         if (g_em->bitmap != debug_bitmap ||
6549             g_em->src_x != debug_src_x ||
6550             g_em->src_y != debug_src_y)
6551         {
6552           static int last_i = -1;
6553
6554           if (i != last_i)
6555           {
6556             printf("\n");
6557             last_i = i;
6558           }
6559
6560           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6561                  p, i, element, element_info[element].token_name,
6562                  element_action_info[effective_action].suffix, direction);
6563
6564           if (element != effective_element)
6565             printf(" [%d ('%s')]",
6566                    effective_element,
6567                    element_info[effective_element].token_name);
6568
6569           printf("\n");
6570
6571           if (g_em->bitmap != debug_bitmap)
6572             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6573                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6574
6575           if (g_em->src_x != debug_src_x ||
6576               g_em->src_y != debug_src_y)
6577             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6578                    j,
6579                    g_em->src_x, g_em->src_y,
6580                    g_em->src_x / 32, g_em->src_y / 32,
6581                    debug_src_x, debug_src_y,
6582                    debug_src_x / 32, debug_src_y / 32);
6583
6584           num_em_gfx_errors++;
6585         }
6586 #endif
6587
6588       }
6589     }
6590   }
6591
6592 #if DEBUG_EM_GFX
6593   printf("\n");
6594   printf("::: [%d errors found]\n", num_em_gfx_errors);
6595
6596   exit(0);
6597 #endif
6598 }
6599
6600 void PlayMenuSoundExt(int sound)
6601 {
6602   if (sound == SND_UNDEFINED)
6603     return;
6604
6605   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6606       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6607     return;
6608
6609   if (IS_LOOP_SOUND(sound))
6610     PlaySoundLoop(sound);
6611   else
6612     PlaySound(sound);
6613 }
6614
6615 void PlayMenuSound()
6616 {
6617   PlayMenuSoundExt(menu.sound[game_status]);
6618 }
6619
6620 void PlayMenuSoundStereo(int sound, int stereo_position)
6621 {
6622   if (sound == SND_UNDEFINED)
6623     return;
6624
6625   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6626       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6627     return;
6628
6629   if (IS_LOOP_SOUND(sound))
6630     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6631   else
6632     PlaySoundStereo(sound, stereo_position);
6633 }
6634
6635 void PlayMenuSoundIfLoopExt(int sound)
6636 {
6637   if (sound == SND_UNDEFINED)
6638     return;
6639
6640   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6641       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6642     return;
6643
6644   if (IS_LOOP_SOUND(sound))
6645     PlaySoundLoop(sound);
6646 }
6647
6648 void PlayMenuSoundIfLoop()
6649 {
6650   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
6651 }
6652
6653 void PlayMenuMusicExt(int music)
6654 {
6655   if (music == MUS_UNDEFINED)
6656     return;
6657
6658   if (!setup.sound_music)
6659     return;
6660
6661   PlayMusic(music);
6662 }
6663
6664 void PlayMenuMusic()
6665 {
6666   PlayMenuMusicExt(menu.music[game_status]);
6667 }
6668
6669 void PlaySoundActivating()
6670 {
6671 #if 0
6672   PlaySound(SND_MENU_ITEM_ACTIVATING);
6673 #endif
6674 }
6675
6676 void PlaySoundSelecting()
6677 {
6678 #if 0
6679   PlaySound(SND_MENU_ITEM_SELECTING);
6680 #endif
6681 }
6682
6683 void ToggleFullscreenIfNeeded()
6684 {
6685   boolean change_fullscreen = (setup.fullscreen !=
6686                                video.fullscreen_enabled);
6687   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6688                                     !strEqual(setup.fullscreen_mode,
6689                                               video.fullscreen_mode_current));
6690
6691   if (!video.fullscreen_available)
6692     return;
6693
6694 #if 1
6695   if (change_fullscreen || change_fullscreen_mode)
6696 #else
6697   if (setup.fullscreen != video.fullscreen_enabled ||
6698       setup.fullscreen_mode != video.fullscreen_mode_current)
6699 #endif
6700   {
6701     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6702
6703     /* save backbuffer content which gets lost when toggling fullscreen mode */
6704     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6705
6706 #if 1
6707     if (change_fullscreen_mode)
6708 #else
6709     if (setup.fullscreen && video.fullscreen_enabled)
6710 #endif
6711     {
6712       /* keep fullscreen, but change fullscreen mode (screen resolution) */
6713 #if 1
6714       /* (this is now set in sdl.c) */
6715 #else
6716       video.fullscreen_mode_current = setup.fullscreen_mode;
6717 #endif
6718       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
6719     }
6720
6721     /* toggle fullscreen */
6722     ChangeVideoModeIfNeeded(setup.fullscreen);
6723
6724     setup.fullscreen = video.fullscreen_enabled;
6725
6726     /* restore backbuffer content from temporary backbuffer backup bitmap */
6727     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6728
6729     FreeBitmap(tmp_backbuffer);
6730
6731 #if 1
6732     /* update visible window/screen */
6733     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6734 #else
6735     redraw_mask = REDRAW_ALL;
6736 #endif
6737   }
6738 }