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