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