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