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