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