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