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