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