rnd-20070312-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22 #include "screens.h"
23
24
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX    0
27
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES        0
30 #define TOOL_CTRL_ID_NO         1
31 #define TOOL_CTRL_ID_CONFIRM    2
32 #define TOOL_CTRL_ID_PLAYER_1   3
33 #define TOOL_CTRL_ID_PLAYER_2   4
34 #define TOOL_CTRL_ID_PLAYER_3   5
35 #define TOOL_CTRL_ID_PLAYER_4   6
36
37 #define NUM_TOOL_BUTTONS        7
38
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
44
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
47
48 static char *print_if_not_empty(int element)
49 {
50   static char *s = NULL;
51   char *token_name = element_info[element].token_name;
52
53   if (s != NULL)
54     free(s);
55
56   s = checked_malloc(strlen(token_name) + 10 + 1);
57
58   if (element != EL_EMPTY)
59     sprintf(s, "%d\t['%s']", element, token_name);
60   else
61     sprintf(s, "%d", element);
62
63   return s;
64 }
65
66 void DumpTile(int x, int y)
67 {
68   int sx = SCREENX(x);
69   int sy = SCREENY(y);
70
71   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
72   {
73     x--;
74     y--;
75   }
76
77   printf_line("-", 79);
78   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
79   printf_line("-", 79);
80
81   if (!IN_LEV_FIELD(x, y))
82   {
83     printf("(not in level field)\n");
84     printf("\n");
85
86     return;
87   }
88
89   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
90          element_info[Feld[x][y]].token_name);
91   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
92   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
93   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
94   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95   printf("  MovPos:      %d\n", MovPos[x][y]);
96   printf("  MovDir:      %d\n", MovDir[x][y]);
97   printf("  MovDelay:    %d\n", MovDelay[x][y]);
98   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
99   printf("  CustomValue: %d\n", CustomValue[x][y]);
100   printf("  GfxElement:  %d\n", GfxElement[x][y]);
101   printf("  GfxAction:   %d\n", GfxAction[x][y]);
102   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
103   printf("\n");
104 }
105
106 void SetDrawtoField(int mode)
107 {
108   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
109   {
110     FX = TILEX;
111     FY = TILEY;
112     BX1 = -1;
113     BY1 = -1;
114     BX2 = SCR_FIELDX;
115     BY2 = SCR_FIELDY;
116     redraw_x1 = 1;
117     redraw_y1 = 1;
118
119     drawto_field = fieldbuffer;
120   }
121   else  /* DRAW_DIRECT, DRAW_BACKBUFFER */
122   {
123     FX = SX;
124     FY = SY;
125     BX1 = 0;
126     BY1 = 0;
127     BX2 = SCR_FIELDX - 1;
128     BY2 = SCR_FIELDY - 1;
129     redraw_x1 = 0;
130     redraw_y1 = 0;
131
132     drawto_field = (mode == DRAW_DIRECT ? window :  backbuffer);
133   }
134 }
135
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 {
138   if (game_status == GAME_MODE_PLAYING &&
139       level.game_engine_type == GAME_ENGINE_TYPE_EM)
140   {
141     /* currently there is no partial redraw -- always redraw whole playfield */
142     RedrawPlayfield_EM(TRUE);
143
144     /* blit playfield from scroll buffer to normal back buffer for fading in */
145     BlitScreenToBitmap_EM(backbuffer);
146   }
147   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
148   {
149     if (force_redraw)
150     {
151       x = gfx.sx - TILEX;
152       y = gfx.sy - TILEY;
153       width = gfx.sxsize + 2 * TILEX;
154       height = gfx.sysize + 2 * TILEY;
155     }
156
157     if (force_redraw || setup.direct_draw)
158     {
159       int xx, yy;
160       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162
163       if (setup.direct_draw)
164         SetDrawtoField(DRAW_BACKBUFFER);
165
166       for (xx = BX1; xx <= BX2; xx++)
167         for (yy = BY1; yy <= BY2; yy++)
168           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
169             DrawScreenField(xx, yy);
170       DrawAllPlayers();
171
172       if (setup.direct_draw)
173         SetDrawtoField(DRAW_DIRECT);
174     }
175
176     if (setup.soft_scrolling)
177     {
178       int fx = FX, fy = FY;
179
180       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
181       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
182
183       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
184     }
185   }
186
187   if (force_redraw)
188   {
189     x = gfx.sx;
190     y = gfx.sy;
191     width = gfx.sxsize;
192     height = gfx.sysize;
193   }
194
195   BlitBitmap(drawto, window, x, y, width, height, x, y);
196 }
197
198 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
199 {
200   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
201
202   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
203   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
204 }
205
206 void DrawMaskedBorder_FIELD()
207 {
208   if (game_status >= GAME_MODE_TITLE &&
209       game_status <= GAME_MODE_PLAYING &&
210       border.draw_masked[game_status])
211     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
212 }
213
214 void DrawMaskedBorder_DOOR_1()
215 {
216   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
217       (game_status != GAME_MODE_EDITOR ||
218        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
219     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
220 }
221
222 void DrawMaskedBorder_DOOR_2()
223 {
224   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
225       game_status != GAME_MODE_EDITOR)
226     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
227 }
228
229 void DrawMaskedBorder_DOOR_3()
230 {
231   /* currently not available */
232 }
233
234 void DrawMaskedBorder_ALL()
235 {
236   DrawMaskedBorder_FIELD();
237   DrawMaskedBorder_DOOR_1();
238   DrawMaskedBorder_DOOR_2();
239   DrawMaskedBorder_DOOR_3();
240 }
241
242 void DrawMaskedBorder(int redraw_mask)
243 {
244   /* do not draw masked screen borders when displaying title screens */
245   if (effectiveGameStatus() == GAME_MODE_TITLE ||
246       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 0
1842   printf("??? %d, %d\n", game_status, font_nr);
1843 #endif
1844
1845 #if 1
1846   max_len_label_text = getMaxTextLength(pos, font_nr);
1847 #else
1848   max_len_label_text = SXSIZE / getFontWidth(font_nr);
1849 #endif
1850
1851 #if 1
1852   if (pos->chars != -1)
1853     max_len_label_text = pos->chars;
1854 #endif
1855
1856   for (i = 0; i < max_len_label_text; i++)
1857     label_text[i] = ' ';
1858   label_text[max_len_label_text] = '\0';
1859
1860   if (strlen(label_text) > 0)
1861   {
1862 #if 1
1863     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1864 #else
1865     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1866     int lypos = MICROLABEL2_YPOS;
1867
1868     DrawText(lxpos, lypos, label_text, font_nr);
1869 #endif
1870   }
1871
1872   strncpy(label_text,
1873           (mode == MICROLABEL_LEVEL_NAME ? level.name :
1874            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
1875            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1876            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
1877            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
1878            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
1879            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
1880           max_len_label_text);
1881   label_text[max_len_label_text] = '\0';
1882
1883   if (strlen(label_text) > 0)
1884   {
1885 #if 1
1886     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1887 #else
1888     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1889     int lypos = MICROLABEL2_YPOS;
1890
1891     DrawText(lxpos, lypos, label_text, font_nr);
1892 #endif
1893   }
1894
1895   redraw_mask |= REDRAW_MICROLEVEL;
1896 }
1897
1898 void DrawPreviewLevel(boolean restart)
1899 {
1900   static unsigned long scroll_delay = 0;
1901   static unsigned long label_delay = 0;
1902   static int from_x, from_y, scroll_direction;
1903   static int label_state, label_counter;
1904   unsigned long scroll_delay_value = preview.step_delay;
1905   boolean show_level_border = (BorderElement != EL_EMPTY);
1906   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1907   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1908   int last_game_status = game_status;           /* save current game status */
1909
1910 #if 0
1911 #if 1
1912   game_status = GAME_MODE_MAIN;
1913 #else
1914   /* force PREVIEW font on preview level */
1915   game_status = GAME_MODE_PSEUDO_PREVIEW;
1916 #endif
1917 #endif
1918
1919   if (restart)
1920   {
1921     from_x = 0;
1922     from_y = 0;
1923
1924     if (preview.anim_mode == ANIM_CENTERED)
1925     {
1926       if (level_xsize > preview.xsize)
1927         from_x = (level_xsize - preview.xsize) / 2;
1928       if (level_ysize > preview.ysize)
1929         from_y = (level_ysize - preview.ysize) / 2;
1930     }
1931
1932     from_x += preview.xoffset;
1933     from_y += preview.yoffset;
1934
1935     scroll_direction = MV_RIGHT;
1936     label_state = 1;
1937     label_counter = 0;
1938
1939     DrawPreviewLevelExt(from_x, from_y);
1940     DrawPreviewLevelLabelExt(label_state);
1941
1942     /* initialize delay counters */
1943     DelayReached(&scroll_delay, 0);
1944     DelayReached(&label_delay, 0);
1945
1946     if (leveldir_current->name)
1947     {
1948       struct TextPosInfo *pos = &menu.main.text.level_info_1;
1949       char label_text[MAX_OUTPUT_LINESIZE + 1];
1950 #if 1
1951       int font_nr = pos->font;
1952 #else
1953       int font_nr = FONT_TEXT_1;
1954 #endif
1955 #if 1
1956       int max_len_label_text = getMaxTextLength(pos, font_nr);
1957 #else
1958       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
1959 #endif
1960 #if 0
1961       int text_width;
1962       int lxpos, lypos;
1963 #endif
1964
1965 #if 1
1966       if (pos->chars != -1)
1967         max_len_label_text = pos->chars;
1968 #endif
1969
1970       strncpy(label_text, leveldir_current->name, max_len_label_text);
1971       label_text[max_len_label_text] = '\0';
1972
1973 #if 1
1974       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
1975 #else
1976       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
1977       lypos = SY + MICROLABEL1_YPOS;
1978
1979       DrawText(lxpos, lypos, label_text, font_nr);
1980 #endif
1981     }
1982
1983     game_status = last_game_status;     /* restore current game status */
1984
1985     return;
1986   }
1987
1988   /* scroll preview level, if needed */
1989   if (preview.anim_mode != ANIM_NONE &&
1990       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
1991       DelayReached(&scroll_delay, scroll_delay_value))
1992   {
1993     switch (scroll_direction)
1994     {
1995       case MV_LEFT:
1996         if (from_x > 0)
1997         {
1998           from_x -= preview.step_offset;
1999           from_x = (from_x < 0 ? 0 : from_x);
2000         }
2001         else
2002           scroll_direction = MV_UP;
2003         break;
2004
2005       case MV_RIGHT:
2006         if (from_x < level_xsize - preview.xsize)
2007         {
2008           from_x += preview.step_offset;
2009           from_x = (from_x > level_xsize - preview.xsize ?
2010                     level_xsize - preview.xsize : from_x);
2011         }
2012         else
2013           scroll_direction = MV_DOWN;
2014         break;
2015
2016       case MV_UP:
2017         if (from_y > 0)
2018         {
2019           from_y -= preview.step_offset;
2020           from_y = (from_y < 0 ? 0 : from_y);
2021         }
2022         else
2023           scroll_direction = MV_RIGHT;
2024         break;
2025
2026       case MV_DOWN:
2027         if (from_y < level_ysize - preview.ysize)
2028         {
2029           from_y += preview.step_offset;
2030           from_y = (from_y > level_ysize - preview.ysize ?
2031                     level_ysize - preview.ysize : from_y);
2032         }
2033         else
2034           scroll_direction = MV_LEFT;
2035         break;
2036
2037       default:
2038         break;
2039     }
2040
2041     DrawPreviewLevelExt(from_x, from_y);
2042   }
2043
2044   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2045   /* redraw micro level label, if needed */
2046   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2047       !strEqual(level.author, ANONYMOUS_NAME) &&
2048       !strEqual(level.author, leveldir_current->name) &&
2049       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2050   {
2051     int max_label_counter = 23;
2052
2053     if (leveldir_current->imported_from != NULL &&
2054         strlen(leveldir_current->imported_from) > 0)
2055       max_label_counter += 14;
2056     if (leveldir_current->imported_by != NULL &&
2057         strlen(leveldir_current->imported_by) > 0)
2058       max_label_counter += 14;
2059
2060     label_counter = (label_counter + 1) % max_label_counter;
2061     label_state = (label_counter >= 0 && label_counter <= 7 ?
2062                    MICROLABEL_LEVEL_NAME :
2063                    label_counter >= 9 && label_counter <= 12 ?
2064                    MICROLABEL_LEVEL_AUTHOR_HEAD :
2065                    label_counter >= 14 && label_counter <= 21 ?
2066                    MICROLABEL_LEVEL_AUTHOR :
2067                    label_counter >= 23 && label_counter <= 26 ?
2068                    MICROLABEL_IMPORTED_FROM_HEAD :
2069                    label_counter >= 28 && label_counter <= 35 ?
2070                    MICROLABEL_IMPORTED_FROM :
2071                    label_counter >= 37 && label_counter <= 40 ?
2072                    MICROLABEL_IMPORTED_BY_HEAD :
2073                    label_counter >= 42 && label_counter <= 49 ?
2074                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2075
2076     if (leveldir_current->imported_from == NULL &&
2077         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2078          label_state == MICROLABEL_IMPORTED_FROM))
2079       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2080                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2081
2082     DrawPreviewLevelLabelExt(label_state);
2083   }
2084
2085   game_status = last_game_status;       /* restore current game status */
2086 }
2087
2088 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2089                                     int graphic, int sync_frame, int mask_mode)
2090 {
2091   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2092
2093   if (mask_mode == USE_MASKING)
2094     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2095   else
2096     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2097 }
2098
2099 inline void DrawGraphicAnimation(int x, int y, int graphic)
2100 {
2101   int lx = LEVELX(x), ly = LEVELY(y);
2102
2103   if (!IN_SCR_FIELD(x, y))
2104     return;
2105
2106   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2107                           graphic, GfxFrame[lx][ly], NO_MASKING);
2108   MarkTileDirty(x, y);
2109 }
2110
2111 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2112 {
2113   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2114 }
2115
2116 void DrawLevelElementAnimation(int x, int y, int element)
2117 {
2118   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2119
2120   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2121 }
2122
2123 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2124 {
2125   int sx = SCREENX(x), sy = SCREENY(y);
2126
2127   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2128     return;
2129
2130   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2131     return;
2132
2133   DrawGraphicAnimation(sx, sy, graphic);
2134
2135 #if 1
2136   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2137     DrawLevelFieldCrumbledSand(x, y);
2138 #else
2139   if (GFX_CRUMBLED(Feld[x][y]))
2140     DrawLevelFieldCrumbledSand(x, y);
2141 #endif
2142 }
2143
2144 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2145 {
2146   int sx = SCREENX(x), sy = SCREENY(y);
2147   int graphic;
2148
2149   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2150     return;
2151
2152   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2153
2154   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2155     return;
2156
2157   DrawGraphicAnimation(sx, sy, graphic);
2158
2159   if (GFX_CRUMBLED(element))
2160     DrawLevelFieldCrumbledSand(x, y);
2161 }
2162
2163 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2164 {
2165   if (player->use_murphy)
2166   {
2167     /* this works only because currently only one player can be "murphy" ... */
2168     static int last_horizontal_dir = MV_LEFT;
2169     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2170
2171     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2172       last_horizontal_dir = move_dir;
2173
2174     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
2175     {
2176       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2177
2178       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2179     }
2180
2181     return graphic;
2182   }
2183   else
2184     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2185 }
2186
2187 static boolean equalGraphics(int graphic1, int graphic2)
2188 {
2189   struct GraphicInfo *g1 = &graphic_info[graphic1];
2190   struct GraphicInfo *g2 = &graphic_info[graphic2];
2191
2192   return (g1->bitmap      == g2->bitmap &&
2193           g1->src_x       == g2->src_x &&
2194           g1->src_y       == g2->src_y &&
2195           g1->anim_frames == g2->anim_frames &&
2196           g1->anim_delay  == g2->anim_delay &&
2197           g1->anim_mode   == g2->anim_mode);
2198 }
2199
2200 void DrawAllPlayers()
2201 {
2202   int i;
2203
2204   for (i = 0; i < MAX_PLAYERS; i++)
2205     if (stored_player[i].active)
2206       DrawPlayer(&stored_player[i]);
2207 }
2208
2209 void DrawPlayerField(int x, int y)
2210 {
2211   if (!IS_PLAYER(x, y))
2212     return;
2213
2214   DrawPlayer(PLAYERINFO(x, y));
2215 }
2216
2217 void DrawPlayer(struct PlayerInfo *player)
2218 {
2219   int jx = player->jx;
2220   int jy = player->jy;
2221   int move_dir = player->MovDir;
2222   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2223   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
2224   int last_jx = (player->is_moving ? jx - dx : jx);
2225   int last_jy = (player->is_moving ? jy - dy : jy);
2226   int next_jx = jx + dx;
2227   int next_jy = jy + dy;
2228   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2229   boolean player_is_opaque = FALSE;
2230   int sx = SCREENX(jx), sy = SCREENY(jy);
2231   int sxx = 0, syy = 0;
2232   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2233   int graphic;
2234   int action = ACTION_DEFAULT;
2235   int last_player_graphic = getPlayerGraphic(player, move_dir);
2236   int last_player_frame = player->Frame;
2237   int frame = 0;
2238
2239   /* GfxElement[][] is set to the element the player is digging or collecting;
2240      remove also for off-screen player if the player is not moving anymore */
2241   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2242     GfxElement[jx][jy] = EL_UNDEFINED;
2243
2244   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2245     return;
2246
2247 #if DEBUG
2248   if (!IN_LEV_FIELD(jx, jy))
2249   {
2250     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2251     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2252     printf("DrawPlayerField(): This should never happen!\n");
2253     return;
2254   }
2255 #endif
2256
2257   if (element == EL_EXPLOSION)
2258     return;
2259
2260   action = (player->is_pushing    ? ACTION_PUSHING         :
2261             player->is_digging    ? ACTION_DIGGING         :
2262             player->is_collecting ? ACTION_COLLECTING      :
2263             player->is_moving     ? ACTION_MOVING          :
2264             player->is_snapping   ? ACTION_SNAPPING        :
2265             player->is_dropping   ? ACTION_DROPPING        :
2266             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
2267
2268   if (player->is_waiting)
2269     move_dir = player->dir_waiting;
2270
2271   InitPlayerGfxAnimation(player, action, move_dir);
2272
2273   /* ----------------------------------------------------------------------- */
2274   /* draw things in the field the player is leaving, if needed               */
2275   /* ----------------------------------------------------------------------- */
2276
2277   if (player->is_moving)
2278   {
2279     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2280     {
2281       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2282
2283       if (last_element == EL_DYNAMITE_ACTIVE ||
2284           last_element == EL_EM_DYNAMITE_ACTIVE ||
2285           last_element == EL_SP_DISK_RED_ACTIVE)
2286         DrawDynamite(last_jx, last_jy);
2287       else
2288         DrawLevelFieldThruMask(last_jx, last_jy);
2289     }
2290     else if (last_element == EL_DYNAMITE_ACTIVE ||
2291              last_element == EL_EM_DYNAMITE_ACTIVE ||
2292              last_element == EL_SP_DISK_RED_ACTIVE)
2293       DrawDynamite(last_jx, last_jy);
2294 #if 0
2295     /* !!! this is not enough to prevent flickering of players which are
2296        moving next to each others without a free tile between them -- this
2297        can only be solved by drawing all players layer by layer (first the
2298        background, then the foreground etc.) !!! => TODO */
2299     else if (!IS_PLAYER(last_jx, last_jy))
2300       DrawLevelField(last_jx, last_jy);
2301 #else
2302     else
2303       DrawLevelField(last_jx, last_jy);
2304 #endif
2305
2306     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2307       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2308   }
2309
2310   if (!IN_SCR_FIELD(sx, sy))
2311     return;
2312
2313   if (setup.direct_draw)
2314     SetDrawtoField(DRAW_BUFFERED);
2315
2316   /* ----------------------------------------------------------------------- */
2317   /* draw things behind the player, if needed                                */
2318   /* ----------------------------------------------------------------------- */
2319
2320   if (Back[jx][jy])
2321     DrawLevelElement(jx, jy, Back[jx][jy]);
2322   else if (IS_ACTIVE_BOMB(element))
2323     DrawLevelElement(jx, jy, EL_EMPTY);
2324   else
2325   {
2326     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2327     {
2328       int old_element = GfxElement[jx][jy];
2329       int old_graphic = el_act_dir2img(old_element, action, move_dir);
2330       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2331
2332       if (GFX_CRUMBLED(old_element))
2333         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2334       else
2335         DrawGraphic(sx, sy, old_graphic, frame);
2336
2337       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2338         player_is_opaque = TRUE;
2339     }
2340     else
2341     {
2342       GfxElement[jx][jy] = EL_UNDEFINED;
2343
2344       /* make sure that pushed elements are drawn with correct frame rate */
2345 #if 1
2346       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2347
2348       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2349         GfxFrame[jx][jy] = player->StepFrame;
2350 #else
2351       if (player->is_pushing && player->is_moving)
2352         GfxFrame[jx][jy] = player->StepFrame;
2353 #endif
2354
2355       DrawLevelField(jx, jy);
2356     }
2357   }
2358
2359   /* ----------------------------------------------------------------------- */
2360   /* draw player himself                                                     */
2361   /* ----------------------------------------------------------------------- */
2362
2363   graphic = getPlayerGraphic(player, move_dir);
2364
2365   /* in the case of changed player action or direction, prevent the current
2366      animation frame from being restarted for identical animations */
2367   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2368     player->Frame = last_player_frame;
2369
2370   frame = getGraphicAnimationFrame(graphic, player->Frame);
2371
2372   if (player->GfxPos)
2373   {
2374     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2375       sxx = player->GfxPos;
2376     else
2377       syy = player->GfxPos;
2378   }
2379
2380   if (!setup.soft_scrolling && ScreenMovPos)
2381     sxx = syy = 0;
2382
2383   if (player_is_opaque)
2384     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2385   else
2386     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2387
2388   if (SHIELD_ON(player))
2389   {
2390     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2391                    IMG_SHIELD_NORMAL_ACTIVE);
2392     int frame = getGraphicAnimationFrame(graphic, -1);
2393
2394     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2395   }
2396
2397   /* ----------------------------------------------------------------------- */
2398   /* draw things the player is pushing, if needed                            */
2399   /* ----------------------------------------------------------------------- */
2400
2401 #if 0
2402   printf("::: %d, %d [%d, %d] [%d]\n",
2403          player->is_pushing, player_is_moving, player->GfxAction,
2404          player->is_moving, player_is_moving);
2405 #endif
2406
2407 #if 1
2408   if (player->is_pushing && player->is_moving)
2409   {
2410     int px = SCREENX(jx), py = SCREENY(jy);
2411     int pxx = (TILEX - ABS(sxx)) * dx;
2412     int pyy = (TILEY - ABS(syy)) * dy;
2413     int gfx_frame = GfxFrame[jx][jy];
2414
2415     int graphic;
2416     int sync_frame;
2417     int frame;
2418
2419     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2420     {
2421       element = Feld[next_jx][next_jy];
2422       gfx_frame = GfxFrame[next_jx][next_jy];
2423     }
2424
2425     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2426
2427 #if 1
2428     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2429     frame = getGraphicAnimationFrame(graphic, sync_frame);
2430 #else
2431     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2432 #endif
2433
2434     /* draw background element under pushed element (like the Sokoban field) */
2435     if (Back[next_jx][next_jy])
2436       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2437
2438     /* masked drawing is needed for EMC style (double) movement graphics */
2439     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2440   }
2441 #endif
2442
2443   /* ----------------------------------------------------------------------- */
2444   /* draw things in front of player (active dynamite or dynabombs)           */
2445   /* ----------------------------------------------------------------------- */
2446
2447   if (IS_ACTIVE_BOMB(element))
2448   {
2449     graphic = el2img(element);
2450     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2451
2452     if (game.emulation == EMU_SUPAPLEX)
2453       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2454     else
2455       DrawGraphicThruMask(sx, sy, graphic, frame);
2456   }
2457
2458   if (player_is_moving && last_element == EL_EXPLOSION)
2459   {
2460     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2461                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2462     int graphic = el_act2img(element, ACTION_EXPLODING);
2463     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2464     int phase = ExplodePhase[last_jx][last_jy] - 1;
2465     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2466
2467     if (phase >= delay)
2468       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2469   }
2470
2471   /* ----------------------------------------------------------------------- */
2472   /* draw elements the player is just walking/passing through/under          */
2473   /* ----------------------------------------------------------------------- */
2474
2475   if (player_is_moving)
2476   {
2477     /* handle the field the player is leaving ... */
2478     if (IS_ACCESSIBLE_INSIDE(last_element))
2479       DrawLevelField(last_jx, last_jy);
2480     else if (IS_ACCESSIBLE_UNDER(last_element))
2481       DrawLevelFieldThruMask(last_jx, last_jy);
2482   }
2483
2484   /* do not redraw accessible elements if the player is just pushing them */
2485   if (!player_is_moving || !player->is_pushing)
2486   {
2487     /* ... and the field the player is entering */
2488     if (IS_ACCESSIBLE_INSIDE(element))
2489       DrawLevelField(jx, jy);
2490     else if (IS_ACCESSIBLE_UNDER(element))
2491       DrawLevelFieldThruMask(jx, jy);
2492   }
2493
2494   if (setup.direct_draw)
2495   {
2496     int dst_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
2497     int dst_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
2498     int x_size = TILEX * (1 + ABS(jx - last_jx));
2499     int y_size = TILEY * (1 + ABS(jy - last_jy));
2500
2501     BlitBitmap(drawto_field, window,
2502                dst_x, dst_y, x_size, y_size, dst_x, dst_y);
2503     SetDrawtoField(DRAW_DIRECT);
2504   }
2505
2506   MarkTileDirty(sx, sy);
2507 }
2508
2509 /* ------------------------------------------------------------------------- */
2510
2511 void WaitForEventToContinue()
2512 {
2513   boolean still_wait = TRUE;
2514
2515   /* simulate releasing mouse button over last gadget, if still pressed */
2516   if (button_status)
2517     HandleGadgets(-1, -1, 0);
2518
2519   button_status = MB_RELEASED;
2520
2521 #if 1
2522   ClearEventQueue();
2523 #endif
2524
2525   while (still_wait)
2526   {
2527     if (PendingEvent())
2528     {
2529       Event event;
2530
2531       NextEvent(&event);
2532
2533       switch (event.type)
2534       {
2535         case EVENT_BUTTONPRESS:
2536         case EVENT_KEYPRESS:
2537           still_wait = FALSE;
2538           break;
2539
2540         case EVENT_KEYRELEASE:
2541           ClearPlayerAction();
2542           break;
2543
2544         default:
2545           HandleOtherEvents(&event);
2546           break;
2547       }
2548     }
2549     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2550     {
2551       still_wait = FALSE;
2552     }
2553
2554     DoAnimation();
2555
2556     /* don't eat all CPU time */
2557     Delay(10);
2558   }
2559 }
2560
2561 #define MAX_REQUEST_LINES               13
2562 #define MAX_REQUEST_LINE_FONT1_LEN      7
2563 #define MAX_REQUEST_LINE_FONT2_LEN      10
2564
2565 boolean Request(char *text, unsigned int req_state)
2566 {
2567   int mx, my, ty, result = -1;
2568   unsigned int old_door_state;
2569   int last_game_status = game_status;   /* save current game status */
2570   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2571   int font_nr = FONT_TEXT_2;
2572   int max_word_len = 0;
2573   char *text_ptr;
2574
2575   for (text_ptr = text; *text_ptr; text_ptr++)
2576   {
2577     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2578
2579     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2580     {
2581       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2582 #if 1
2583       font_nr = FONT_TEXT_1;
2584 #else
2585       font_nr = FONT_LEVEL_NUMBER;
2586 #endif
2587
2588       break;
2589     }
2590   }
2591
2592   if (game_status == GAME_MODE_PLAYING &&
2593       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2594     BlitScreenToBitmap_EM(backbuffer);
2595
2596   /* disable deactivated drawing when quick-loading level tape recording */
2597   if (tape.playing && tape.deactivate_display)
2598     TapeDeactivateDisplayOff(TRUE);
2599
2600   SetMouseCursor(CURSOR_DEFAULT);
2601
2602 #if defined(NETWORK_AVALIABLE)
2603   /* pause network game while waiting for request to answer */
2604   if (options.network &&
2605       game_status == GAME_MODE_PLAYING &&
2606       req_state & REQUEST_WAIT_FOR_INPUT)
2607     SendToServer_PausePlaying();
2608 #endif
2609
2610   old_door_state = GetDoorState();
2611
2612   /* simulate releasing mouse button over last gadget, if still pressed */
2613   if (button_status)
2614     HandleGadgets(-1, -1, 0);
2615
2616   UnmapAllGadgets();
2617
2618   if (old_door_state & DOOR_OPEN_1)
2619   {
2620     CloseDoor(DOOR_CLOSE_1);
2621
2622     /* save old door content */
2623     BlitBitmap(bitmap_db_door, bitmap_db_door,
2624                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2625                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2626   }
2627
2628 #if 1
2629   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2630 #endif
2631
2632   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2633
2634   /* clear door drawing field */
2635   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2636
2637   /* force DOOR font on preview level */
2638   game_status = GAME_MODE_PSEUDO_DOOR;
2639
2640   /* write text for request */
2641   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2642   {
2643     char text_line[max_request_line_len + 1];
2644     int tx, tl, tc = 0;
2645
2646     if (!*text)
2647       break;
2648
2649     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2650     {
2651       tc = *(text + tx);
2652       if (!tc || tc == ' ')
2653         break;
2654     }
2655
2656     if (!tl)
2657     { 
2658       text++; 
2659       ty--; 
2660       continue; 
2661     }
2662
2663     strncpy(text_line, text, tl);
2664     text_line[tl] = 0;
2665
2666     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2667              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2668              text_line, font_nr);
2669
2670     text += tl + (tc == ' ' ? 1 : 0);
2671   }
2672
2673   game_status = last_game_status;       /* restore current game status */
2674
2675   if (req_state & REQ_ASK)
2676   {
2677     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2678     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2679   }
2680   else if (req_state & REQ_CONFIRM)
2681   {
2682     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2683   }
2684   else if (req_state & REQ_PLAYER)
2685   {
2686     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2687     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2688     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2689     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2690   }
2691
2692   /* copy request gadgets to door backbuffer */
2693   BlitBitmap(drawto, bitmap_db_door,
2694              DX, DY, DXSIZE, DYSIZE,
2695              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2696
2697   OpenDoor(DOOR_OPEN_1);
2698
2699   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2700   {
2701     if (game_status == GAME_MODE_PLAYING)
2702     {
2703       SetPanelBackground();
2704       SetDrawBackgroundMask(REDRAW_DOOR_1);
2705     }
2706     else
2707     {
2708       SetDrawBackgroundMask(REDRAW_FIELD);
2709     }
2710
2711     return FALSE;
2712   }
2713
2714   if (game_status != GAME_MODE_MAIN)
2715     InitAnimation();
2716
2717   button_status = MB_RELEASED;
2718
2719   request_gadget_id = -1;
2720
2721   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2722
2723   while (result < 0)
2724   {
2725     if (PendingEvent())
2726     {
2727       Event event;
2728
2729       NextEvent(&event);
2730
2731       switch (event.type)
2732       {
2733         case EVENT_BUTTONPRESS:
2734         case EVENT_BUTTONRELEASE:
2735         case EVENT_MOTIONNOTIFY:
2736         {
2737           if (event.type == EVENT_MOTIONNOTIFY)
2738           {
2739             if (!PointerInWindow(window))
2740               continue; /* window and pointer are on different screens */
2741
2742             if (!button_status)
2743               continue;
2744
2745             motion_status = TRUE;
2746             mx = ((MotionEvent *) &event)->x;
2747             my = ((MotionEvent *) &event)->y;
2748           }
2749           else
2750           {
2751             motion_status = FALSE;
2752             mx = ((ButtonEvent *) &event)->x;
2753             my = ((ButtonEvent *) &event)->y;
2754             if (event.type == EVENT_BUTTONPRESS)
2755               button_status = ((ButtonEvent *) &event)->button;
2756             else
2757               button_status = MB_RELEASED;
2758           }
2759
2760           /* this sets 'request_gadget_id' */
2761           HandleGadgets(mx, my, button_status);
2762
2763           switch (request_gadget_id)
2764           {
2765             case TOOL_CTRL_ID_YES:
2766               result = TRUE;
2767               break;
2768             case TOOL_CTRL_ID_NO:
2769               result = FALSE;
2770               break;
2771             case TOOL_CTRL_ID_CONFIRM:
2772               result = TRUE | FALSE;
2773               break;
2774
2775             case TOOL_CTRL_ID_PLAYER_1:
2776               result = 1;
2777               break;
2778             case TOOL_CTRL_ID_PLAYER_2:
2779               result = 2;
2780               break;
2781             case TOOL_CTRL_ID_PLAYER_3:
2782               result = 3;
2783               break;
2784             case TOOL_CTRL_ID_PLAYER_4:
2785               result = 4;
2786               break;
2787
2788             default:
2789               break;
2790           }
2791
2792           break;
2793         }
2794
2795         case EVENT_KEYPRESS:
2796           switch (GetEventKey((KeyEvent *)&event, TRUE))
2797           {
2798             case KSYM_Return:
2799               result = 1;
2800               break;
2801
2802             case KSYM_Escape:
2803               result = 0;
2804               break;
2805
2806             default:
2807               break;
2808           }
2809           if (req_state & REQ_PLAYER)
2810             result = 0;
2811           break;
2812
2813         case EVENT_KEYRELEASE:
2814           ClearPlayerAction();
2815           break;
2816
2817         default:
2818           HandleOtherEvents(&event);
2819           break;
2820       }
2821     }
2822     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2823     {
2824       int joy = AnyJoystick();
2825
2826       if (joy & JOY_BUTTON_1)
2827         result = 1;
2828       else if (joy & JOY_BUTTON_2)
2829         result = 0;
2830     }
2831
2832 #if 1
2833
2834     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
2835     {
2836       HandleGameActions();
2837       BackToFront();
2838     }
2839     else
2840     {
2841       DoAnimation();
2842
2843       if (!PendingEvent())      /* delay only if no pending events */
2844         Delay(10);
2845     }
2846
2847 #else
2848
2849     DoAnimation();
2850
2851 #if 1
2852     if (!PendingEvent())        /* delay only if no pending events */
2853       Delay(10);
2854 #else
2855     /* don't eat all CPU time */
2856     Delay(10);
2857 #endif
2858
2859 #endif
2860   }
2861
2862   if (game_status != GAME_MODE_MAIN)
2863     StopAnimation();
2864
2865   UnmapToolButtons();
2866
2867   if (!(req_state & REQ_STAY_OPEN))
2868   {
2869     CloseDoor(DOOR_CLOSE_1);
2870
2871     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
2872         (req_state & REQ_REOPEN))
2873       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
2874   }
2875
2876   RemapAllGadgets();
2877
2878   if (game_status == GAME_MODE_PLAYING)
2879   {
2880     SetPanelBackground();
2881     SetDrawBackgroundMask(REDRAW_DOOR_1);
2882   }
2883   else
2884   {
2885     SetDrawBackgroundMask(REDRAW_FIELD);
2886   }
2887
2888 #if defined(NETWORK_AVALIABLE)
2889   /* continue network game after request */
2890   if (options.network &&
2891       game_status == GAME_MODE_PLAYING &&
2892       req_state & REQUEST_WAIT_FOR_INPUT)
2893     SendToServer_ContinuePlaying();
2894 #endif
2895
2896   /* restore deactivated drawing when quick-loading level tape recording */
2897   if (tape.playing && tape.deactivate_display)
2898     TapeDeactivateDisplayOn();
2899
2900   return result;
2901 }
2902
2903 unsigned int OpenDoor(unsigned int door_state)
2904 {
2905   if (door_state & DOOR_COPY_BACK)
2906   {
2907     if (door_state & DOOR_OPEN_1)
2908       BlitBitmap(bitmap_db_door, bitmap_db_door,
2909                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2910                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2911
2912     if (door_state & DOOR_OPEN_2)
2913       BlitBitmap(bitmap_db_door, bitmap_db_door,
2914                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
2915                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2916
2917     door_state &= ~DOOR_COPY_BACK;
2918   }
2919
2920   return MoveDoor(door_state);
2921 }
2922
2923 unsigned int CloseDoor(unsigned int door_state)
2924 {
2925   unsigned int old_door_state = GetDoorState();
2926
2927   if (!(door_state & DOOR_NO_COPY_BACK))
2928   {
2929     if (old_door_state & DOOR_OPEN_1)
2930       BlitBitmap(backbuffer, bitmap_db_door,
2931                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2932
2933     if (old_door_state & DOOR_OPEN_2)
2934       BlitBitmap(backbuffer, bitmap_db_door,
2935                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2936
2937     door_state &= ~DOOR_NO_COPY_BACK;
2938   }
2939
2940   return MoveDoor(door_state);
2941 }
2942
2943 unsigned int GetDoorState()
2944 {
2945   return MoveDoor(DOOR_GET_STATE);
2946 }
2947
2948 unsigned int SetDoorState(unsigned int door_state)
2949 {
2950   return MoveDoor(door_state | DOOR_SET_STATE);
2951 }
2952
2953 unsigned int MoveDoor(unsigned int door_state)
2954 {
2955   static int door1 = DOOR_OPEN_1;
2956   static int door2 = DOOR_CLOSE_2;
2957   unsigned long door_delay = 0;
2958   unsigned long door_delay_value;
2959   int stepsize = 1;
2960
2961   if (door_1.width < 0 || door_1.width > DXSIZE)
2962     door_1.width = DXSIZE;
2963   if (door_1.height < 0 || door_1.height > DYSIZE)
2964     door_1.height = DYSIZE;
2965   if (door_2.width < 0 || door_2.width > VXSIZE)
2966     door_2.width = VXSIZE;
2967   if (door_2.height < 0 || door_2.height > VYSIZE)
2968     door_2.height = VYSIZE;
2969
2970   if (door_state == DOOR_GET_STATE)
2971     return (door1 | door2);
2972
2973   if (door_state & DOOR_SET_STATE)
2974   {
2975     if (door_state & DOOR_ACTION_1)
2976       door1 = door_state & DOOR_ACTION_1;
2977     if (door_state & DOOR_ACTION_2)
2978       door2 = door_state & DOOR_ACTION_2;
2979
2980     return (door1 | door2);
2981   }
2982
2983   if (!(door_state & DOOR_FORCE_REDRAW))
2984   {
2985     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2986       door_state &= ~DOOR_OPEN_1;
2987     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2988       door_state &= ~DOOR_CLOSE_1;
2989     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2990       door_state &= ~DOOR_OPEN_2;
2991     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2992       door_state &= ~DOOR_CLOSE_2;
2993   }
2994
2995   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
2996                       door_2.step_delay);
2997
2998   if (setup.quick_doors)
2999   {
3000     stepsize = 20;              /* must be choosen to always draw last frame */
3001     door_delay_value = 0;
3002   }
3003
3004   if (global.autoplay_leveldir)
3005   {
3006     door_state |= DOOR_NO_DELAY;
3007     door_state &= ~DOOR_CLOSE_ALL;
3008   }
3009
3010   if (door_state & DOOR_ACTION)
3011   {
3012     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3013     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3014     boolean door_1_done = (!handle_door_1);
3015     boolean door_2_done = (!handle_door_2);
3016     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3017     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3018     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3019     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3020     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3021     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3022     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
3023     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3024     int door_skip = max_door_size - door_size;
3025     int end = door_size;
3026     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3027     int k;
3028
3029     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3030     {
3031       /* opening door sound has priority over simultaneously closing door */
3032       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3033         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3034       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3035         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3036     }
3037
3038     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3039     {
3040       int x = k;
3041       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3042       GC gc = bitmap->stored_clip_gc;
3043
3044       if (door_state & DOOR_ACTION_1)
3045       {
3046         int a = MIN(x * door_1.step_offset, end);
3047         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3048         int i = p + door_skip;
3049
3050         if (door_1.anim_mode & ANIM_STATIC_PANEL)
3051         {
3052           BlitBitmap(bitmap_db_door, drawto,
3053                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3054                      DXSIZE, DYSIZE, DX, DY);
3055         }
3056         else if (x <= a)
3057         {
3058           BlitBitmap(bitmap_db_door, drawto,
3059                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3060                      DXSIZE, DYSIZE - p / 2, DX, DY);
3061
3062           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3063         }
3064
3065         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3066         {
3067           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3068           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3069           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
3070           int dst2_x = DX,              dst2_y = DY;
3071           int width = i, height = DYSIZE;
3072
3073           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3074           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3075                            dst1_x, dst1_y);
3076
3077           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3078           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3079                            dst2_x, dst2_y);
3080         }
3081         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3082         {
3083           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3084           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
3085           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3086           int dst2_x = DX,              dst2_y = DY;
3087           int width = DXSIZE, height = i;
3088
3089           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3090           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3091                            dst1_x, dst1_y);
3092
3093           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3094           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3095                            dst2_x, dst2_y);
3096         }
3097         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
3098         {
3099           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3100
3101           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3102           BlitBitmapMasked(bitmap, drawto,
3103                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3104                            DX + DXSIZE - i, DY + j);
3105           BlitBitmapMasked(bitmap, drawto,
3106                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3107                            DX + DXSIZE - i, DY + 140 + j);
3108           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3109                         DY - (DOOR_GFX_PAGEY1 + j));
3110           BlitBitmapMasked(bitmap, drawto,
3111                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3112                            DX, DY);
3113           BlitBitmapMasked(bitmap, drawto,
3114                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3115                            DX, DY + 140 - j);
3116
3117           BlitBitmapMasked(bitmap, drawto,
3118                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3119                            DX, DY + 77 - j);
3120           BlitBitmapMasked(bitmap, drawto,
3121                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3122                            DX, DY + 203 - j);
3123           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3124           BlitBitmapMasked(bitmap, drawto,
3125                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3126                            DX + DXSIZE - i, DY + 77 + j);
3127           BlitBitmapMasked(bitmap, drawto,
3128                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3129                            DX + DXSIZE - i, DY + 203 + j);
3130         }
3131
3132         redraw_mask |= REDRAW_DOOR_1;
3133         door_1_done = (a == end);
3134       }
3135
3136       if (door_state & DOOR_ACTION_2)
3137       {
3138         int a = MIN(x * door_2.step_offset, door_size);
3139         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3140         int i = p + door_skip;
3141
3142         if (door_2.anim_mode & ANIM_STATIC_PANEL)
3143         {
3144           BlitBitmap(bitmap_db_door, drawto,
3145                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3146                      VXSIZE, VYSIZE, VX, VY);
3147         }
3148         else if (x <= VYSIZE)
3149         {
3150           BlitBitmap(bitmap_db_door, drawto,
3151                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3152                      VXSIZE, VYSIZE - p / 2, VX, VY);
3153
3154           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3155         }
3156
3157         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3158         {
3159           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3160           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3161           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
3162           int dst2_x = VX,              dst2_y = VY;
3163           int width = i, height = VYSIZE;
3164
3165           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3166           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3167                            dst1_x, dst1_y);
3168
3169           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3170           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3171                            dst2_x, dst2_y);
3172         }
3173         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3174         {
3175           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3176           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
3177           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3178           int dst2_x = VX,              dst2_y = VY;
3179           int width = VXSIZE, height = i;
3180
3181           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3182           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3183                            dst1_x, dst1_y);
3184
3185           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3186           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3187                            dst2_x, dst2_y);
3188         }
3189         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
3190         {
3191           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3192
3193           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3194           BlitBitmapMasked(bitmap, drawto,
3195                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3196                            VX + VXSIZE - i, VY + j);
3197           SetClipOrigin(bitmap, gc,
3198                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3199           BlitBitmapMasked(bitmap, drawto,
3200                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3201                            VX, VY);
3202
3203           BlitBitmapMasked(bitmap, drawto,
3204                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3205                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3206           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3207           BlitBitmapMasked(bitmap, drawto,
3208                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3209                            i, VYSIZE / 2 - j,
3210                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3211         }
3212
3213         redraw_mask |= REDRAW_DOOR_2;
3214         door_2_done = (a == VXSIZE);
3215       }
3216
3217       if (!(door_state & DOOR_NO_DELAY))
3218       {
3219         BackToFront();
3220
3221         if (game_status == GAME_MODE_MAIN)
3222           DoAnimation();
3223
3224         WaitUntilDelayReached(&door_delay, door_delay_value);
3225       }
3226     }
3227   }
3228
3229   if (door_state & DOOR_ACTION_1)
3230     door1 = door_state & DOOR_ACTION_1;
3231   if (door_state & DOOR_ACTION_2)
3232     door2 = door_state & DOOR_ACTION_2;
3233
3234   return (door1 | door2);
3235 }
3236
3237 void DrawSpecialEditorDoor()
3238 {
3239   /* draw bigger toolbox window */
3240   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3241              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3242              EX - 4, EY - 12);
3243   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3244              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3245              EX - 6, EY - 4);
3246
3247   redraw_mask |= REDRAW_ALL;
3248 }
3249
3250 void UndrawSpecialEditorDoor()
3251 {
3252   /* draw normal tape recorder window */
3253   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3254              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3255              EX - 6, EY - 12);
3256
3257   redraw_mask |= REDRAW_ALL;
3258 }
3259
3260
3261 /* ---------- new tool button stuff ---------------------------------------- */
3262
3263 /* graphic position values for tool buttons */
3264 #define TOOL_BUTTON_YES_XPOS            2
3265 #define TOOL_BUTTON_YES_YPOS            250
3266 #define TOOL_BUTTON_YES_GFX_YPOS        0
3267 #define TOOL_BUTTON_YES_XSIZE           46
3268 #define TOOL_BUTTON_YES_YSIZE           28
3269 #define TOOL_BUTTON_NO_XPOS             52
3270 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
3271 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
3272 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
3273 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
3274 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
3275 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
3276 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
3277 #define TOOL_BUTTON_CONFIRM_XSIZE       96
3278 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
3279 #define TOOL_BUTTON_PLAYER_XSIZE        30
3280 #define TOOL_BUTTON_PLAYER_YSIZE        30
3281 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
3282 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3283 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3284 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3285 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3286                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3287 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3288                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3289 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3290                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3291 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3292                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3293 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3294                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3295 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3296                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3297 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3298                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3299 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3300                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3301
3302 static struct
3303 {
3304   int xpos, ypos;
3305   int x, y;
3306   int width, height;
3307   int gadget_id;
3308   char *infotext;
3309 } toolbutton_info[NUM_TOOL_BUTTONS] =
3310 {
3311   {
3312     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3313     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3314     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3315     TOOL_CTRL_ID_YES,
3316     "yes"
3317   },
3318   {
3319     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3320     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3321     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3322     TOOL_CTRL_ID_NO,
3323     "no"
3324   },
3325   {
3326     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3327     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3328     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3329     TOOL_CTRL_ID_CONFIRM,
3330     "confirm"
3331   },
3332   {
3333     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3334     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3335     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3336     TOOL_CTRL_ID_PLAYER_1,
3337     "player 1"
3338   },
3339   {
3340     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3341     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3342     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3343     TOOL_CTRL_ID_PLAYER_2,
3344     "player 2"
3345   },
3346   {
3347     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3348     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3349     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3350     TOOL_CTRL_ID_PLAYER_3,
3351     "player 3"
3352   },
3353   {
3354     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3355     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3356     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3357     TOOL_CTRL_ID_PLAYER_4,
3358     "player 4"
3359   }
3360 };
3361
3362 void CreateToolButtons()
3363 {
3364   int i;
3365
3366   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3367   {
3368     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3369     Bitmap *deco_bitmap = None;
3370     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3371     struct GadgetInfo *gi;
3372     unsigned long event_mask;
3373     int gd_xoffset, gd_yoffset;
3374     int gd_x1, gd_x2, gd_y;
3375     int id = i;
3376
3377     event_mask = GD_EVENT_RELEASED;
3378
3379     gd_xoffset = toolbutton_info[i].xpos;
3380     gd_yoffset = toolbutton_info[i].ypos;
3381     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3382     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3383     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3384
3385     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3386     {
3387       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3388
3389       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3390                            &deco_bitmap, &deco_x, &deco_y);
3391       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3392       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3393     }
3394
3395     gi = CreateGadget(GDI_CUSTOM_ID, id,
3396                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3397                       GDI_X, DX + toolbutton_info[i].x,
3398                       GDI_Y, DY + toolbutton_info[i].y,
3399                       GDI_WIDTH, toolbutton_info[i].width,
3400                       GDI_HEIGHT, toolbutton_info[i].height,
3401                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3402                       GDI_STATE, GD_BUTTON_UNPRESSED,
3403                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3404                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3405                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3406                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3407                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3408                       GDI_DECORATION_SHIFTING, 1, 1,
3409                       GDI_DIRECT_DRAW, FALSE,
3410                       GDI_EVENT_MASK, event_mask,
3411                       GDI_CALLBACK_ACTION, HandleToolButtons,
3412                       GDI_END);
3413
3414     if (gi == NULL)
3415       Error(ERR_EXIT, "cannot create gadget");
3416
3417     tool_gadget[id] = gi;
3418   }
3419 }
3420
3421 void FreeToolButtons()
3422 {
3423   int i;
3424
3425   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3426     FreeGadget(tool_gadget[i]);
3427 }
3428
3429 static void UnmapToolButtons()
3430 {
3431   int i;
3432
3433   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3434     UnmapGadget(tool_gadget[i]);
3435 }
3436
3437 static void HandleToolButtons(struct GadgetInfo *gi)
3438 {
3439   request_gadget_id = gi->custom_id;
3440 }
3441
3442 static struct Mapping_EM_to_RND_object
3443 {
3444   int element_em;
3445   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3446   boolean is_backside;                  /* backside of moving element */
3447
3448   int element_rnd;
3449   int action;
3450   int direction;
3451 }
3452 em_object_mapping_list[] =
3453 {
3454   {
3455     Xblank,                             TRUE,   FALSE,
3456     EL_EMPTY,                           -1, -1
3457   },
3458   {
3459     Yacid_splash_eB,                    FALSE,  FALSE,
3460     EL_ACID_SPLASH_RIGHT,               -1, -1
3461   },
3462   {
3463     Yacid_splash_wB,                    FALSE,  FALSE,
3464     EL_ACID_SPLASH_LEFT,                -1, -1
3465   },
3466
3467 #ifdef EM_ENGINE_BAD_ROLL
3468   {
3469     Xstone_force_e,                     FALSE,  FALSE,
3470     EL_ROCK,                            -1, MV_BIT_RIGHT
3471   },
3472   {
3473     Xstone_force_w,                     FALSE,  FALSE,
3474     EL_ROCK,                            -1, MV_BIT_LEFT
3475   },
3476   {
3477     Xnut_force_e,                       FALSE,  FALSE,
3478     EL_NUT,                             -1, MV_BIT_RIGHT
3479   },
3480   {
3481     Xnut_force_w,                       FALSE,  FALSE,
3482     EL_NUT,                             -1, MV_BIT_LEFT
3483   },
3484   {
3485     Xspring_force_e,                    FALSE,  FALSE,
3486     EL_SPRING,                          -1, MV_BIT_RIGHT
3487   },
3488   {
3489     Xspring_force_w,                    FALSE,  FALSE,
3490     EL_SPRING,                          -1, MV_BIT_LEFT
3491   },
3492   {
3493     Xemerald_force_e,                   FALSE,  FALSE,
3494     EL_EMERALD,                         -1, MV_BIT_RIGHT
3495   },
3496   {
3497     Xemerald_force_w,                   FALSE,  FALSE,
3498     EL_EMERALD,                         -1, MV_BIT_LEFT
3499   },
3500   {
3501     Xdiamond_force_e,                   FALSE,  FALSE,
3502     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3503   },
3504   {
3505     Xdiamond_force_w,                   FALSE,  FALSE,
3506     EL_DIAMOND,                         -1, MV_BIT_LEFT
3507   },
3508   {
3509     Xbomb_force_e,                      FALSE,  FALSE,
3510     EL_BOMB,                            -1, MV_BIT_RIGHT
3511   },
3512   {
3513     Xbomb_force_w,                      FALSE,  FALSE,
3514     EL_BOMB,                            -1, MV_BIT_LEFT
3515   },
3516 #endif  /* EM_ENGINE_BAD_ROLL */
3517
3518   {
3519     Xstone,                             TRUE,   FALSE,
3520     EL_ROCK,                            -1, -1
3521   },
3522   {
3523     Xstone_pause,                       FALSE,  FALSE,
3524     EL_ROCK,                            -1, -1
3525   },
3526   {
3527     Xstone_fall,                        FALSE,  FALSE,
3528     EL_ROCK,                            -1, -1
3529   },
3530   {
3531     Ystone_s,                           FALSE,  FALSE,
3532     EL_ROCK,                            ACTION_FALLING, -1
3533   },
3534   {
3535     Ystone_sB,                          FALSE,  TRUE,
3536     EL_ROCK,                            ACTION_FALLING, -1
3537   },
3538   {
3539     Ystone_e,                           FALSE,  FALSE,
3540     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3541   },
3542   {
3543     Ystone_eB,                          FALSE,  TRUE,
3544     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3545   },
3546   {
3547     Ystone_w,                           FALSE,  FALSE,
3548     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3549   },
3550   {
3551     Ystone_wB,                          FALSE,  TRUE,
3552     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3553   },
3554   {
3555     Xnut,                               TRUE,   FALSE,
3556     EL_NUT,                             -1, -1
3557   },
3558   {
3559     Xnut_pause,                         FALSE,  FALSE,
3560     EL_NUT,                             -1, -1
3561   },
3562   {
3563     Xnut_fall,                          FALSE,  FALSE,
3564     EL_NUT,                             -1, -1
3565   },
3566   {
3567     Ynut_s,                             FALSE,  FALSE,
3568     EL_NUT,                             ACTION_FALLING, -1
3569   },
3570   {
3571     Ynut_sB,                            FALSE,  TRUE,
3572     EL_NUT,                             ACTION_FALLING, -1
3573   },
3574   {
3575     Ynut_e,                             FALSE,  FALSE,
3576     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3577   },
3578   {
3579     Ynut_eB,                            FALSE,  TRUE,
3580     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3581   },
3582   {
3583     Ynut_w,                             FALSE,  FALSE,
3584     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3585   },
3586   {
3587     Ynut_wB,                            FALSE,  TRUE,
3588     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3589   },
3590   {
3591     Xbug_n,                             TRUE,   FALSE,
3592     EL_BUG_UP,                          -1, -1
3593   },
3594   {
3595     Xbug_e,                             TRUE,   FALSE,
3596     EL_BUG_RIGHT,                       -1, -1
3597   },
3598   {
3599     Xbug_s,                             TRUE,   FALSE,
3600     EL_BUG_DOWN,                        -1, -1
3601   },
3602   {
3603     Xbug_w,                             TRUE,   FALSE,
3604     EL_BUG_LEFT,                        -1, -1
3605   },
3606   {
3607     Xbug_gon,                           FALSE,  FALSE,
3608     EL_BUG_UP,                          -1, -1
3609   },
3610   {
3611     Xbug_goe,                           FALSE,  FALSE,
3612     EL_BUG_RIGHT,                       -1, -1
3613   },
3614   {
3615     Xbug_gos,                           FALSE,  FALSE,
3616     EL_BUG_DOWN,                        -1, -1
3617   },
3618   {
3619     Xbug_gow,                           FALSE,  FALSE,
3620     EL_BUG_LEFT,                        -1, -1
3621   },
3622   {
3623     Ybug_n,                             FALSE,  FALSE,
3624     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3625   },
3626   {
3627     Ybug_nB,                            FALSE,  TRUE,
3628     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3629   },
3630   {
3631     Ybug_e,                             FALSE,  FALSE,
3632     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3633   },
3634   {
3635     Ybug_eB,                            FALSE,  TRUE,
3636     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3637   },
3638   {
3639     Ybug_s,                             FALSE,  FALSE,
3640     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3641   },
3642   {
3643     Ybug_sB,                            FALSE,  TRUE,
3644     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3645   },
3646   {
3647     Ybug_w,                             FALSE,  FALSE,
3648     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3649   },
3650   {
3651     Ybug_wB,                            FALSE,  TRUE,
3652     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3653   },
3654   {
3655     Ybug_w_n,                           FALSE,  FALSE,
3656     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3657   },
3658   {
3659     Ybug_n_e,                           FALSE,  FALSE,
3660     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3661   },
3662   {
3663     Ybug_e_s,                           FALSE,  FALSE,
3664     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3665   },
3666   {
3667     Ybug_s_w,                           FALSE,  FALSE,
3668     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3669   },
3670   {
3671     Ybug_e_n,                           FALSE,  FALSE,
3672     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3673   },
3674   {
3675     Ybug_s_e,                           FALSE,  FALSE,
3676     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3677   },
3678   {
3679     Ybug_w_s,                           FALSE,  FALSE,
3680     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3681   },
3682   {
3683     Ybug_n_w,                           FALSE,  FALSE,
3684     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3685   },
3686   {
3687     Ybug_stone,                         FALSE,  FALSE,
3688     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3689   },
3690   {
3691     Ybug_spring,                        FALSE,  FALSE,
3692     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3693   },
3694   {
3695     Xtank_n,                            TRUE,   FALSE,
3696     EL_SPACESHIP_UP,                    -1, -1
3697   },
3698   {
3699     Xtank_e,                            TRUE,   FALSE,
3700     EL_SPACESHIP_RIGHT,                 -1, -1
3701   },
3702   {
3703     Xtank_s,                            TRUE,   FALSE,
3704     EL_SPACESHIP_DOWN,                  -1, -1
3705   },
3706   {
3707     Xtank_w,                            TRUE,   FALSE,
3708     EL_SPACESHIP_LEFT,                  -1, -1
3709   },
3710   {
3711     Xtank_gon,                          FALSE,  FALSE,
3712     EL_SPACESHIP_UP,                    -1, -1
3713   },
3714   {
3715     Xtank_goe,                          FALSE,  FALSE,
3716     EL_SPACESHIP_RIGHT,                 -1, -1
3717   },
3718   {
3719     Xtank_gos,                          FALSE,  FALSE,
3720     EL_SPACESHIP_DOWN,                  -1, -1
3721   },
3722   {
3723     Xtank_gow,                          FALSE,  FALSE,
3724     EL_SPACESHIP_LEFT,                  -1, -1
3725   },
3726   {
3727     Ytank_n,                            FALSE,  FALSE,
3728     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3729   },
3730   {
3731     Ytank_nB,                           FALSE,  TRUE,
3732     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3733   },
3734   {
3735     Ytank_e,                            FALSE,  FALSE,
3736     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3737   },
3738   {
3739     Ytank_eB,                           FALSE,  TRUE,
3740     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3741   },
3742   {
3743     Ytank_s,                            FALSE,  FALSE,
3744     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3745   },
3746   {
3747     Ytank_sB,                           FALSE,  TRUE,
3748     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3749   },
3750   {
3751     Ytank_w,                            FALSE,  FALSE,
3752     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3753   },
3754   {
3755     Ytank_wB,                           FALSE,  TRUE,
3756     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3757   },
3758   {
3759     Ytank_w_n,                          FALSE,  FALSE,
3760     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3761   },
3762   {
3763     Ytank_n_e,                          FALSE,  FALSE,
3764     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3765   },
3766   {
3767     Ytank_e_s,                          FALSE,  FALSE,
3768     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3769   },
3770   {
3771     Ytank_s_w,                          FALSE,  FALSE,
3772     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3773   },
3774   {
3775     Ytank_e_n,                          FALSE,  FALSE,
3776     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3777   },
3778   {
3779     Ytank_s_e,                          FALSE,  FALSE,
3780     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3781   },
3782   {
3783     Ytank_w_s,                          FALSE,  FALSE,
3784     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3785   },
3786   {
3787     Ytank_n_w,                          FALSE,  FALSE,
3788     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3789   },
3790   {
3791     Ytank_stone,                        FALSE,  FALSE,
3792     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
3793   },
3794   {
3795     Ytank_spring,                       FALSE,  FALSE,
3796     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
3797   },
3798   {
3799     Xandroid,                           TRUE,   FALSE,
3800     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
3801   },
3802   {
3803     Xandroid_1_n,                       FALSE,  FALSE,
3804     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3805   },
3806   {
3807     Xandroid_2_n,                       FALSE,  FALSE,
3808     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
3809   },
3810   {
3811     Xandroid_1_e,                       FALSE,  FALSE,
3812     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3813   },
3814   {
3815     Xandroid_2_e,                       FALSE,  FALSE,
3816     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
3817   },
3818   {
3819     Xandroid_1_w,                       FALSE,  FALSE,
3820     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3821   },
3822   {
3823     Xandroid_2_w,                       FALSE,  FALSE,
3824     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
3825   },
3826   {
3827     Xandroid_1_s,                       FALSE,  FALSE,
3828     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3829   },
3830   {
3831     Xandroid_2_s,                       FALSE,  FALSE,
3832     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
3833   },
3834   {
3835     Yandroid_n,                         FALSE,  FALSE,
3836     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3837   },
3838   {
3839     Yandroid_nB,                        FALSE,  TRUE,
3840     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
3841   },
3842   {
3843     Yandroid_ne,                        FALSE,  FALSE,
3844     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
3845   },
3846   {
3847     Yandroid_neB,                       FALSE,  TRUE,
3848     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
3849   },
3850   {
3851     Yandroid_e,                         FALSE,  FALSE,
3852     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3853   },
3854   {
3855     Yandroid_eB,                        FALSE,  TRUE,
3856     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
3857   },
3858   {
3859     Yandroid_se,                        FALSE,  FALSE,
3860     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
3861   },
3862   {
3863     Yandroid_seB,                       FALSE,  TRUE,
3864     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
3865   },
3866   {
3867     Yandroid_s,                         FALSE,  FALSE,
3868     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3869   },
3870   {
3871     Yandroid_sB,                        FALSE,  TRUE,
3872     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
3873   },
3874   {
3875     Yandroid_sw,                        FALSE,  FALSE,
3876     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
3877   },
3878   {
3879     Yandroid_swB,                       FALSE,  TRUE,
3880     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
3881   },
3882   {
3883     Yandroid_w,                         FALSE,  FALSE,
3884     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3885   },
3886   {
3887     Yandroid_wB,                        FALSE,  TRUE,
3888     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
3889   },
3890   {
3891     Yandroid_nw,                        FALSE,  FALSE,
3892     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
3893   },
3894   {
3895     Yandroid_nwB,                       FALSE,  TRUE,
3896     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
3897   },
3898   {
3899     Xspring,                            TRUE,   FALSE,
3900     EL_SPRING,                          -1, -1
3901   },
3902   {
3903     Xspring_pause,                      FALSE,  FALSE,
3904     EL_SPRING,                          -1, -1
3905   },
3906   {
3907     Xspring_e,                          FALSE,  FALSE,
3908     EL_SPRING,                          -1, -1
3909   },
3910   {
3911     Xspring_w,                          FALSE,  FALSE,
3912     EL_SPRING,                          -1, -1
3913   },
3914   {
3915     Xspring_fall,                       FALSE,  FALSE,
3916     EL_SPRING,                          -1, -1
3917   },
3918   {
3919     Yspring_s,                          FALSE,  FALSE,
3920     EL_SPRING,                          ACTION_FALLING, -1
3921   },
3922   {
3923     Yspring_sB,                         FALSE,  TRUE,
3924     EL_SPRING,                          ACTION_FALLING, -1
3925   },
3926   {
3927     Yspring_e,                          FALSE,  FALSE,
3928     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3929   },
3930   {
3931     Yspring_eB,                         FALSE,  TRUE,
3932     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
3933   },
3934   {
3935     Yspring_w,                          FALSE,  FALSE,
3936     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3937   },
3938   {
3939     Yspring_wB,                         FALSE,  TRUE,
3940     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
3941   },
3942   {
3943     Yspring_kill_e,                     FALSE,  FALSE,
3944     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3945   },
3946   {
3947     Yspring_kill_eB,                    FALSE,  TRUE,
3948     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
3949   },
3950   {
3951     Yspring_kill_w,                     FALSE,  FALSE,
3952     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3953   },
3954   {
3955     Yspring_kill_wB,                    FALSE,  TRUE,
3956     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
3957   },
3958   {
3959     Xeater_n,                           TRUE,   FALSE,
3960     EL_YAMYAM_UP,                       -1, -1
3961   },
3962   {
3963     Xeater_e,                           TRUE,   FALSE,
3964     EL_YAMYAM_RIGHT,                    -1, -1
3965   },
3966   {
3967     Xeater_w,                           TRUE,   FALSE,
3968     EL_YAMYAM_LEFT,                     -1, -1
3969   },
3970   {
3971     Xeater_s,                           TRUE,   FALSE,
3972     EL_YAMYAM_DOWN,                     -1, -1
3973   },
3974   {
3975     Yeater_n,                           FALSE,  FALSE,
3976     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3977   },
3978   {
3979     Yeater_nB,                          FALSE,  TRUE,
3980     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
3981   },
3982   {
3983     Yeater_e,                           FALSE,  FALSE,
3984     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3985   },
3986   {
3987     Yeater_eB,                          FALSE,  TRUE,
3988     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
3989   },
3990   {
3991     Yeater_s,                           FALSE,  FALSE,
3992     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3993   },
3994   {
3995     Yeater_sB,                          FALSE,  TRUE,
3996     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
3997   },
3998   {
3999     Yeater_w,                           FALSE,  FALSE,
4000     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4001   },
4002   {
4003     Yeater_wB,                          FALSE,  TRUE,
4004     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4005   },
4006   {
4007     Yeater_stone,                       FALSE,  FALSE,
4008     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
4009   },
4010   {
4011     Yeater_spring,                      FALSE,  FALSE,
4012     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
4013   },
4014   {
4015     Xalien,                             TRUE,   FALSE,
4016     EL_ROBOT,                           -1, -1
4017   },
4018   {
4019     Xalien_pause,                       FALSE,  FALSE,
4020     EL_ROBOT,                           -1, -1
4021   },
4022   {
4023     Yalien_n,                           FALSE,  FALSE,
4024     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4025   },
4026   {
4027     Yalien_nB,                          FALSE,  TRUE,
4028     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4029   },
4030   {
4031     Yalien_e,                           FALSE,  FALSE,
4032     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4033   },
4034   {
4035     Yalien_eB,                          FALSE,  TRUE,
4036     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4037   },
4038   {
4039     Yalien_s,                           FALSE,  FALSE,
4040     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4041   },
4042   {
4043     Yalien_sB,                          FALSE,  TRUE,
4044     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4045   },
4046   {
4047     Yalien_w,                           FALSE,  FALSE,
4048     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4049   },
4050   {
4051     Yalien_wB,                          FALSE,  TRUE,
4052     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4053   },
4054   {
4055     Yalien_stone,                       FALSE,  FALSE,
4056     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
4057   },
4058   {
4059     Yalien_spring,                      FALSE,  FALSE,
4060     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
4061   },
4062   {
4063     Xemerald,                           TRUE,   FALSE,
4064     EL_EMERALD,                         -1, -1
4065   },
4066   {
4067     Xemerald_pause,                     FALSE,  FALSE,
4068     EL_EMERALD,                         -1, -1
4069   },
4070   {
4071     Xemerald_fall,                      FALSE,  FALSE,
4072     EL_EMERALD,                         -1, -1
4073   },
4074   {
4075     Xemerald_shine,                     FALSE,  FALSE,
4076     EL_EMERALD,                         ACTION_TWINKLING, -1
4077   },
4078   {
4079     Yemerald_s,                         FALSE,  FALSE,
4080     EL_EMERALD,                         ACTION_FALLING, -1
4081   },
4082   {
4083     Yemerald_sB,                        FALSE,  TRUE,
4084     EL_EMERALD,                         ACTION_FALLING, -1
4085   },
4086   {
4087     Yemerald_e,                         FALSE,  FALSE,
4088     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4089   },
4090   {
4091     Yemerald_eB,                        FALSE,  TRUE,
4092     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4093   },
4094   {
4095     Yemerald_w,                         FALSE,  FALSE,
4096     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4097   },
4098   {
4099     Yemerald_wB,                        FALSE,  TRUE,
4100     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4101   },
4102   {
4103     Yemerald_eat,                       FALSE,  FALSE,
4104     EL_EMERALD,                         ACTION_COLLECTING, -1
4105   },
4106   {
4107     Yemerald_stone,                     FALSE,  FALSE,
4108     EL_NUT,                             ACTION_BREAKING, -1
4109   },
4110   {
4111     Xdiamond,                           TRUE,   FALSE,
4112     EL_DIAMOND,                         -1, -1
4113   },
4114   {
4115     Xdiamond_pause,                     FALSE,  FALSE,
4116     EL_DIAMOND,                         -1, -1
4117   },
4118   {
4119     Xdiamond_fall,                      FALSE,  FALSE,
4120     EL_DIAMOND,                         -1, -1
4121   },
4122   {
4123     Xdiamond_shine,                     FALSE,  FALSE,
4124     EL_DIAMOND,                         ACTION_TWINKLING, -1
4125   },
4126   {
4127     Ydiamond_s,                         FALSE,  FALSE,
4128     EL_DIAMOND,                         ACTION_FALLING, -1
4129   },
4130   {
4131     Ydiamond_sB,                        FALSE,  TRUE,
4132     EL_DIAMOND,                         ACTION_FALLING, -1
4133   },
4134   {
4135     Ydiamond_e,                         FALSE,  FALSE,
4136     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4137   },
4138   {
4139     Ydiamond_eB,                        FALSE,  TRUE,
4140     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4141   },
4142   {
4143     Ydiamond_w,                         FALSE,  FALSE,
4144     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4145   },
4146   {
4147     Ydiamond_wB,                        FALSE,  TRUE,
4148     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4149   },
4150   {
4151     Ydiamond_eat,                       FALSE,  FALSE,
4152     EL_DIAMOND,                         ACTION_COLLECTING, -1
4153   },
4154   {
4155     Ydiamond_stone,                     FALSE,  FALSE,
4156     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
4157   },
4158   {
4159     Xdrip_fall,                         TRUE,   FALSE,
4160     EL_AMOEBA_DROP,                     -1, -1
4161   },
4162   {
4163     Xdrip_stretch,                      FALSE,  FALSE,
4164     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4165   },
4166   {
4167     Xdrip_stretchB,                     FALSE,  TRUE,
4168     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4169   },
4170   {
4171     Xdrip_eat,                          FALSE,  FALSE,
4172     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
4173   },
4174   {
4175     Ydrip_s1,                           FALSE,  FALSE,
4176     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4177   },
4178   {
4179     Ydrip_s1B,                          FALSE,  TRUE,
4180     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4181   },
4182   {
4183     Ydrip_s2,                           FALSE,  FALSE,
4184     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4185   },
4186   {
4187     Ydrip_s2B,                          FALSE,  TRUE,
4188     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4189   },
4190   {
4191     Xbomb,                              TRUE,   FALSE,
4192     EL_BOMB,                            -1, -1
4193   },
4194   {
4195     Xbomb_pause,                        FALSE,  FALSE,
4196     EL_BOMB,                            -1, -1
4197   },
4198   {
4199     Xbomb_fall,                         FALSE,  FALSE,
4200     EL_BOMB,                            -1, -1
4201   },
4202   {
4203     Ybomb_s,                            FALSE,  FALSE,
4204     EL_BOMB,                            ACTION_FALLING, -1
4205   },
4206   {
4207     Ybomb_sB,                           FALSE,  TRUE,
4208     EL_BOMB,                            ACTION_FALLING, -1
4209   },
4210   {
4211     Ybomb_e,                            FALSE,  FALSE,
4212     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4213   },
4214   {
4215     Ybomb_eB,                           FALSE,  TRUE,
4216     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4217   },
4218   {
4219     Ybomb_w,                            FALSE,  FALSE,
4220     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4221   },
4222   {
4223     Ybomb_wB,                           FALSE,  TRUE,
4224     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4225   },
4226   {
4227     Ybomb_eat,                          FALSE,  FALSE,
4228     EL_BOMB,                            ACTION_ACTIVATING, -1
4229   },
4230   {
4231     Xballoon,                           TRUE,   FALSE,
4232     EL_BALLOON,                         -1, -1
4233   },
4234   {
4235     Yballoon_n,                         FALSE,  FALSE,
4236     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4237   },
4238   {
4239     Yballoon_nB,                        FALSE,  TRUE,
4240     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4241   },
4242   {
4243     Yballoon_e,                         FALSE,  FALSE,
4244     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4245   },
4246   {
4247     Yballoon_eB,                        FALSE,  TRUE,
4248     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4249   },
4250   {
4251     Yballoon_s,                         FALSE,  FALSE,
4252     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4253   },
4254   {
4255     Yballoon_sB,                        FALSE,  TRUE,
4256     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4257   },
4258   {
4259     Yballoon_w,                         FALSE,  FALSE,
4260     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4261   },
4262   {
4263     Yballoon_wB,                        FALSE,  TRUE,
4264     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4265   },
4266   {
4267     Xgrass,                             TRUE,   FALSE,
4268     EL_EMC_GRASS,                       -1, -1
4269   },
4270   {
4271     Ygrass_nB,                          FALSE,  FALSE,
4272     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
4273   },
4274   {
4275     Ygrass_eB,                          FALSE,  FALSE,
4276     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
4277   },
4278   {
4279     Ygrass_sB,                          FALSE,  FALSE,
4280     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
4281   },
4282   {
4283     Ygrass_wB,                          FALSE,  FALSE,
4284     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4285   },
4286   {
4287     Xdirt,                              TRUE,   FALSE,
4288     EL_SAND,                            -1, -1
4289   },
4290   {
4291     Ydirt_nB,                           FALSE,  FALSE,
4292     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4293   },
4294   {
4295     Ydirt_eB,                           FALSE,  FALSE,
4296     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4297   },
4298   {
4299     Ydirt_sB,                           FALSE,  FALSE,
4300     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4301   },
4302   {
4303     Ydirt_wB,                           FALSE,  FALSE,
4304     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4305   },
4306   {
4307     Xacid_ne,                           TRUE,   FALSE,
4308     EL_ACID_POOL_TOPRIGHT,              -1, -1
4309   },
4310   {
4311     Xacid_se,                           TRUE,   FALSE,
4312     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4313   },
4314   {
4315     Xacid_s,                            TRUE,   FALSE,
4316     EL_ACID_POOL_BOTTOM,                -1, -1
4317   },
4318   {
4319     Xacid_sw,                           TRUE,   FALSE,
4320     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4321   },
4322   {
4323     Xacid_nw,                           TRUE,   FALSE,
4324     EL_ACID_POOL_TOPLEFT,               -1, -1
4325   },
4326   {
4327     Xacid_1,                            TRUE,   FALSE,
4328     EL_ACID,                            -1, -1
4329   },
4330   {
4331     Xacid_2,                            FALSE,  FALSE,
4332     EL_ACID,                            -1, -1
4333   },
4334   {
4335     Xacid_3,                            FALSE,  FALSE,
4336     EL_ACID,                            -1, -1
4337   },
4338   {
4339     Xacid_4,                            FALSE,  FALSE,
4340     EL_ACID,                            -1, -1
4341   },
4342   {
4343     Xacid_5,                            FALSE,  FALSE,
4344     EL_ACID,                            -1, -1
4345   },
4346   {
4347     Xacid_6,                            FALSE,  FALSE,
4348     EL_ACID,                            -1, -1
4349   },
4350   {
4351     Xacid_7,                            FALSE,  FALSE,
4352     EL_ACID,                            -1, -1
4353   },
4354   {
4355     Xacid_8,                            FALSE,  FALSE,
4356     EL_ACID,                            -1, -1
4357   },
4358   {
4359     Xball_1,                            TRUE,   FALSE,
4360     EL_EMC_MAGIC_BALL,                  -1, -1
4361   },
4362   {
4363     Xball_1B,                           FALSE,  FALSE,
4364     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4365   },
4366   {
4367     Xball_2,                            FALSE,  FALSE,
4368     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4369   },
4370   {
4371     Xball_2B,                           FALSE,  FALSE,
4372     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4373   },
4374   {
4375     Yball_eat,                          FALSE,  FALSE,
4376     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4377   },
4378   {
4379     Ykey_1_eat,                         FALSE,  FALSE,
4380     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4381   },
4382   {
4383     Ykey_2_eat,                         FALSE,  FALSE,
4384     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4385   },
4386   {
4387     Ykey_3_eat,                         FALSE,  FALSE,
4388     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4389   },
4390   {
4391     Ykey_4_eat,                         FALSE,  FALSE,
4392     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4393   },
4394   {
4395     Ykey_5_eat,                         FALSE,  FALSE,
4396     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4397   },
4398   {
4399     Ykey_6_eat,                         FALSE,  FALSE,
4400     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4401   },
4402   {
4403     Ykey_7_eat,                         FALSE,  FALSE,
4404     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4405   },
4406   {
4407     Ykey_8_eat,                         FALSE,  FALSE,
4408     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4409   },
4410   {
4411     Ylenses_eat,                        FALSE,  FALSE,
4412     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4413   },
4414   {
4415     Ymagnify_eat,                       FALSE,  FALSE,
4416     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4417   },
4418   {
4419     Ygrass_eat,                         FALSE,  FALSE,
4420     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4421   },
4422   {
4423     Ydirt_eat,                          FALSE,  FALSE,
4424     EL_SAND,                            ACTION_SNAPPING, -1
4425   },
4426   {
4427     Xgrow_ns,                           TRUE,   FALSE,
4428     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4429   },
4430   {
4431     Ygrow_ns_eat,                       FALSE,  FALSE,
4432     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4433   },
4434   {
4435     Xgrow_ew,                           TRUE,   FALSE,
4436     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4437   },
4438   {
4439     Ygrow_ew_eat,                       FALSE,  FALSE,
4440     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4441   },
4442   {
4443     Xwonderwall,                        TRUE,   FALSE,
4444     EL_MAGIC_WALL,                      -1, -1
4445   },
4446   {
4447     XwonderwallB,                       FALSE,  FALSE,
4448     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4449   },
4450   {
4451     Xamoeba_1,                          TRUE,   FALSE,
4452     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4453   },
4454   {
4455     Xamoeba_2,                          FALSE,  FALSE,
4456     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4457   },
4458   {
4459     Xamoeba_3,                          FALSE,  FALSE,
4460     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4461   },
4462   {
4463     Xamoeba_4,                          FALSE,  FALSE,
4464     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4465   },
4466   {
4467     Xamoeba_5,                          TRUE,   FALSE,
4468     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4469   },
4470   {
4471     Xamoeba_6,                          FALSE,  FALSE,
4472     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4473   },
4474   {
4475     Xamoeba_7,                          FALSE,  FALSE,
4476     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4477   },
4478   {
4479     Xamoeba_8,                          FALSE,  FALSE,
4480     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4481   },
4482   {
4483     Xdoor_1,                            TRUE,   FALSE,
4484     EL_EM_GATE_1,                       -1, -1
4485   },
4486   {
4487     Xdoor_2,                            TRUE,   FALSE,
4488     EL_EM_GATE_2,                       -1, -1
4489   },
4490   {
4491     Xdoor_3,                            TRUE,   FALSE,
4492     EL_EM_GATE_3,                       -1, -1
4493   },
4494   {
4495     Xdoor_4,                            TRUE,   FALSE,
4496     EL_EM_GATE_4,                       -1, -1
4497   },
4498   {
4499     Xdoor_5,                            TRUE,   FALSE,
4500     EL_EMC_GATE_5,                      -1, -1
4501   },
4502   {
4503     Xdoor_6,                            TRUE,   FALSE,
4504     EL_EMC_GATE_6,                      -1, -1
4505   },
4506   {
4507     Xdoor_7,                            TRUE,   FALSE,
4508     EL_EMC_GATE_7,                      -1, -1
4509   },
4510   {
4511     Xdoor_8,                            TRUE,   FALSE,
4512     EL_EMC_GATE_8,                      -1, -1
4513   },
4514   {
4515     Xkey_1,                             TRUE,   FALSE,
4516     EL_EM_KEY_1,                        -1, -1
4517   },
4518   {
4519     Xkey_2,                             TRUE,   FALSE,
4520     EL_EM_KEY_2,                        -1, -1
4521   },
4522   {
4523     Xkey_3,                             TRUE,   FALSE,
4524     EL_EM_KEY_3,                        -1, -1
4525   },
4526   {
4527     Xkey_4,                             TRUE,   FALSE,
4528     EL_EM_KEY_4,                        -1, -1
4529   },
4530   {
4531     Xkey_5,                             TRUE,   FALSE,
4532     EL_EMC_KEY_5,                       -1, -1
4533   },
4534   {
4535     Xkey_6,                             TRUE,   FALSE,
4536     EL_EMC_KEY_6,                       -1, -1
4537   },
4538   {
4539     Xkey_7,                             TRUE,   FALSE,
4540     EL_EMC_KEY_7,                       -1, -1
4541   },
4542   {
4543     Xkey_8,                             TRUE,   FALSE,
4544     EL_EMC_KEY_8,                       -1, -1
4545   },
4546   {
4547     Xwind_n,                            TRUE,   FALSE,
4548     EL_BALLOON_SWITCH_UP,               -1, -1
4549   },
4550   {
4551     Xwind_e,                            TRUE,   FALSE,
4552     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4553   },
4554   {
4555     Xwind_s,                            TRUE,   FALSE,
4556     EL_BALLOON_SWITCH_DOWN,             -1, -1
4557   },
4558   {
4559     Xwind_w,                            TRUE,   FALSE,
4560     EL_BALLOON_SWITCH_LEFT,             -1, -1
4561   },
4562   {
4563     Xwind_nesw,                         TRUE,   FALSE,
4564     EL_BALLOON_SWITCH_ANY,              -1, -1
4565   },
4566   {
4567     Xwind_stop,                         TRUE,   FALSE,
4568     EL_BALLOON_SWITCH_NONE,             -1, -1
4569   },
4570   {
4571     Xexit,                              TRUE,   FALSE,
4572     EL_EM_EXIT_CLOSED,                  -1, -1
4573   },
4574   {
4575     Xexit_1,                            TRUE,   FALSE,
4576     EL_EM_EXIT_OPEN,                    -1, -1
4577   },
4578   {
4579     Xexit_2,                            FALSE,  FALSE,
4580     EL_EM_EXIT_OPEN,                    -1, -1
4581   },
4582   {
4583     Xexit_3,                            FALSE,  FALSE,
4584     EL_EM_EXIT_OPEN,                    -1, -1
4585   },
4586   {
4587     Xdynamite,                          TRUE,   FALSE,
4588     EL_EM_DYNAMITE,                     -1, -1
4589   },
4590   {
4591     Ydynamite_eat,                      FALSE,  FALSE,
4592     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4593   },
4594   {
4595     Xdynamite_1,                        TRUE,   FALSE,
4596     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4597   },
4598   {
4599     Xdynamite_2,                        FALSE,  FALSE,
4600     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4601   },
4602   {
4603     Xdynamite_3,                        FALSE,  FALSE,
4604     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4605   },
4606   {
4607     Xdynamite_4,                        FALSE,  FALSE,
4608     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4609   },
4610   {
4611     Xbumper,                            TRUE,   FALSE,
4612     EL_EMC_SPRING_BUMPER,               -1, -1
4613   },
4614   {
4615     XbumperB,                           FALSE,  FALSE,
4616     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4617   },
4618   {
4619     Xwheel,                             TRUE,   FALSE,
4620     EL_ROBOT_WHEEL,                     -1, -1
4621   },
4622   {
4623     XwheelB,                            FALSE,  FALSE,
4624     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4625   },
4626   {
4627     Xswitch,                            TRUE,   FALSE,
4628     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4629   },
4630   {
4631     XswitchB,                           FALSE,  FALSE,
4632     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4633   },
4634   {
4635     Xsand,                              TRUE,   FALSE,
4636     EL_QUICKSAND_EMPTY,                 -1, -1
4637   },
4638   {
4639     Xsand_stone,                        TRUE,   FALSE,
4640     EL_QUICKSAND_FULL,                  -1, -1
4641   },
4642   {
4643     Xsand_stonein_1,                    FALSE,  TRUE,
4644     EL_ROCK,                            ACTION_FILLING, -1
4645   },
4646   {
4647     Xsand_stonein_2,                    FALSE,  TRUE,
4648     EL_ROCK,                            ACTION_FILLING, -1
4649   },
4650   {
4651     Xsand_stonein_3,                    FALSE,  TRUE,
4652     EL_ROCK,                            ACTION_FILLING, -1
4653   },
4654   {
4655     Xsand_stonein_4,                    FALSE,  TRUE,
4656     EL_ROCK,                            ACTION_FILLING, -1
4657   },
4658   {
4659     Xsand_stonesand_1,                  FALSE,  FALSE,
4660     EL_QUICKSAND_FULL,                  -1, -1
4661   },
4662   {
4663     Xsand_stonesand_2,                  FALSE,  FALSE,
4664     EL_QUICKSAND_FULL,                  -1, -1
4665   },
4666   {
4667     Xsand_stonesand_3,                  FALSE,  FALSE,
4668     EL_QUICKSAND_FULL,                  -1, -1
4669   },
4670   {
4671     Xsand_stonesand_4,                  FALSE,  FALSE,
4672     EL_QUICKSAND_FULL,                  -1, -1
4673   },
4674   {
4675     Xsand_stoneout_1,                   FALSE,  FALSE,
4676     EL_ROCK,                            ACTION_EMPTYING, -1
4677   },
4678   {
4679     Xsand_stoneout_2,                   FALSE,  FALSE,
4680     EL_ROCK,                            ACTION_EMPTYING, -1
4681   },
4682   {
4683     Xsand_sandstone_1,                  FALSE,  FALSE,
4684     EL_QUICKSAND_FULL,                  -1, -1
4685   },
4686   {
4687     Xsand_sandstone_2,                  FALSE,  FALSE,
4688     EL_QUICKSAND_FULL,                  -1, -1
4689   },
4690   {
4691     Xsand_sandstone_3,                  FALSE,  FALSE,
4692     EL_QUICKSAND_FULL,                  -1, -1
4693   },
4694   {
4695     Xsand_sandstone_4,                  FALSE,  FALSE,
4696     EL_QUICKSAND_FULL,                  -1, -1
4697   },
4698   {
4699     Xplant,                             TRUE,   FALSE,
4700     EL_EMC_PLANT,                       -1, -1
4701   },
4702   {
4703     Yplant,                             FALSE,  FALSE,
4704     EL_EMC_PLANT,                       -1, -1
4705   },
4706   {
4707     Xlenses,                            TRUE,   FALSE,
4708     EL_EMC_LENSES,                      -1, -1
4709   },
4710   {
4711     Xmagnify,                           TRUE,   FALSE,
4712     EL_EMC_MAGNIFIER,                   -1, -1
4713   },
4714   {
4715     Xdripper,                           TRUE,   FALSE,
4716     EL_EMC_DRIPPER,                     -1, -1
4717   },
4718   {
4719     XdripperB,                          FALSE,  FALSE,
4720     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4721   },
4722   {
4723     Xfake_blank,                        TRUE,   FALSE,
4724     EL_INVISIBLE_WALL,                  -1, -1
4725   },
4726   {
4727     Xfake_blankB,                       FALSE,  FALSE,
4728     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4729   },
4730   {
4731     Xfake_grass,                        TRUE,   FALSE,
4732     EL_EMC_FAKE_GRASS,                  -1, -1
4733   },
4734   {
4735     Xfake_grassB,                       FALSE,  FALSE,
4736     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4737   },
4738   {
4739     Xfake_door_1,                       TRUE,   FALSE,
4740     EL_EM_GATE_1_GRAY,                  -1, -1
4741   },
4742   {
4743     Xfake_door_2,                       TRUE,   FALSE,
4744     EL_EM_GATE_2_GRAY,                  -1, -1
4745   },
4746   {
4747     Xfake_door_3,                       TRUE,   FALSE,
4748     EL_EM_GATE_3_GRAY,                  -1, -1
4749   },
4750   {
4751     Xfake_door_4,                       TRUE,   FALSE,
4752     EL_EM_GATE_4_GRAY,                  -1, -1
4753   },
4754   {
4755     Xfake_door_5,                       TRUE,   FALSE,
4756     EL_EMC_GATE_5_GRAY,                 -1, -1
4757   },
4758   {
4759     Xfake_door_6,                       TRUE,   FALSE,
4760     EL_EMC_GATE_6_GRAY,                 -1, -1
4761   },
4762   {
4763     Xfake_door_7,                       TRUE,   FALSE,
4764     EL_EMC_GATE_7_GRAY,                 -1, -1
4765   },
4766   {
4767     Xfake_door_8,                       TRUE,   FALSE,
4768     EL_EMC_GATE_8_GRAY,                 -1, -1
4769   },
4770   {
4771     Xfake_acid_1,                       TRUE,   FALSE,
4772     EL_EMC_FAKE_ACID,                   -1, -1
4773   },
4774   {
4775     Xfake_acid_2,                       FALSE,  FALSE,
4776     EL_EMC_FAKE_ACID,                   -1, -1
4777   },
4778   {
4779     Xfake_acid_3,                       FALSE,  FALSE,
4780     EL_EMC_FAKE_ACID,                   -1, -1
4781   },
4782   {
4783     Xfake_acid_4,                       FALSE,  FALSE,
4784     EL_EMC_FAKE_ACID,                   -1, -1
4785   },
4786   {
4787     Xfake_acid_5,                       FALSE,  FALSE,
4788     EL_EMC_FAKE_ACID,                   -1, -1
4789   },
4790   {
4791     Xfake_acid_6,                       FALSE,  FALSE,
4792     EL_EMC_FAKE_ACID,                   -1, -1
4793   },
4794   {
4795     Xfake_acid_7,                       FALSE,  FALSE,
4796     EL_EMC_FAKE_ACID,                   -1, -1
4797   },
4798   {
4799     Xfake_acid_8,                       FALSE,  FALSE,
4800     EL_EMC_FAKE_ACID,                   -1, -1
4801   },
4802   {
4803     Xsteel_1,                           TRUE,   FALSE,
4804     EL_STEELWALL,                       -1, -1
4805   },
4806   {
4807     Xsteel_2,                           TRUE,   FALSE,
4808     EL_EMC_STEELWALL_2,                 -1, -1
4809   },
4810   {
4811     Xsteel_3,                           TRUE,   FALSE,
4812     EL_EMC_STEELWALL_3,                 -1, -1
4813   },
4814   {
4815     Xsteel_4,                           TRUE,   FALSE,
4816     EL_EMC_STEELWALL_4,                 -1, -1
4817   },
4818   {
4819     Xwall_1,                            TRUE,   FALSE,
4820     EL_WALL,                            -1, -1
4821   },
4822   {
4823     Xwall_2,                            TRUE,   FALSE,
4824     EL_EMC_WALL_14,                     -1, -1
4825   },
4826   {
4827     Xwall_3,                            TRUE,   FALSE,
4828     EL_EMC_WALL_15,                     -1, -1
4829   },
4830   {
4831     Xwall_4,                            TRUE,   FALSE,
4832     EL_EMC_WALL_16,                     -1, -1
4833   },
4834   {
4835     Xround_wall_1,                      TRUE,   FALSE,
4836     EL_WALL_SLIPPERY,                   -1, -1
4837   },
4838   {
4839     Xround_wall_2,                      TRUE,   FALSE,
4840     EL_EMC_WALL_SLIPPERY_2,             -1, -1
4841   },
4842   {
4843     Xround_wall_3,                      TRUE,   FALSE,
4844     EL_EMC_WALL_SLIPPERY_3,             -1, -1
4845   },
4846   {
4847     Xround_wall_4,                      TRUE,   FALSE,
4848     EL_EMC_WALL_SLIPPERY_4,             -1, -1
4849   },
4850   {
4851     Xdecor_1,                           TRUE,   FALSE,
4852     EL_EMC_WALL_8,                      -1, -1
4853   },
4854   {
4855     Xdecor_2,                           TRUE,   FALSE,
4856     EL_EMC_WALL_6,                      -1, -1
4857   },
4858   {
4859     Xdecor_3,                           TRUE,   FALSE,
4860     EL_EMC_WALL_4,                      -1, -1
4861   },
4862   {
4863     Xdecor_4,                           TRUE,   FALSE,
4864     EL_EMC_WALL_7,                      -1, -1
4865   },
4866   {
4867     Xdecor_5,                           TRUE,   FALSE,
4868     EL_EMC_WALL_5,                      -1, -1
4869   },
4870   {
4871     Xdecor_6,                           TRUE,   FALSE,
4872     EL_EMC_WALL_9,                      -1, -1
4873   },
4874   {
4875     Xdecor_7,                           TRUE,   FALSE,
4876     EL_EMC_WALL_10,                     -1, -1
4877   },
4878   {
4879     Xdecor_8,                           TRUE,   FALSE,
4880     EL_EMC_WALL_1,                      -1, -1
4881   },
4882   {
4883     Xdecor_9,                           TRUE,   FALSE,
4884     EL_EMC_WALL_2,                      -1, -1
4885   },
4886   {
4887     Xdecor_10,                          TRUE,   FALSE,
4888     EL_EMC_WALL_3,                      -1, -1
4889   },
4890   {
4891     Xdecor_11,                          TRUE,   FALSE,
4892     EL_EMC_WALL_11,                     -1, -1
4893   },
4894   {
4895     Xdecor_12,                          TRUE,   FALSE,
4896     EL_EMC_WALL_12,                     -1, -1
4897   },
4898   {
4899     Xalpha_0,                           TRUE,   FALSE,
4900     EL_CHAR('0'),                       -1, -1
4901   },
4902   {
4903     Xalpha_1,                           TRUE,   FALSE,
4904     EL_CHAR('1'),                       -1, -1
4905   },
4906   {
4907     Xalpha_2,                           TRUE,   FALSE,
4908     EL_CHAR('2'),                       -1, -1
4909   },
4910   {
4911     Xalpha_3,                           TRUE,   FALSE,
4912     EL_CHAR('3'),                       -1, -1
4913   },
4914   {
4915     Xalpha_4,                           TRUE,   FALSE,
4916     EL_CHAR('4'),                       -1, -1
4917   },
4918   {
4919     Xalpha_5,                           TRUE,   FALSE,
4920     EL_CHAR('5'),                       -1, -1
4921   },
4922   {
4923     Xalpha_6,                           TRUE,   FALSE,
4924     EL_CHAR('6'),                       -1, -1
4925   },
4926   {
4927     Xalpha_7,                           TRUE,   FALSE,
4928     EL_CHAR('7'),                       -1, -1
4929   },
4930   {
4931     Xalpha_8,                           TRUE,   FALSE,
4932     EL_CHAR('8'),                       -1, -1
4933   },
4934   {
4935     Xalpha_9,                           TRUE,   FALSE,
4936     EL_CHAR('9'),                       -1, -1
4937   },
4938   {
4939     Xalpha_excla,                       TRUE,   FALSE,
4940     EL_CHAR('!'),                       -1, -1
4941   },
4942   {
4943     Xalpha_quote,                       TRUE,   FALSE,
4944     EL_CHAR('"'),                       -1, -1
4945   },
4946   {
4947     Xalpha_comma,                       TRUE,   FALSE,
4948     EL_CHAR(','),                       -1, -1
4949   },
4950   {
4951     Xalpha_minus,                       TRUE,   FALSE,
4952     EL_CHAR('-'),                       -1, -1
4953   },
4954   {
4955     Xalpha_perio,                       TRUE,   FALSE,
4956     EL_CHAR('.'),                       -1, -1
4957   },
4958   {
4959     Xalpha_colon,                       TRUE,   FALSE,
4960     EL_CHAR(':'),                       -1, -1
4961   },
4962   {
4963     Xalpha_quest,                       TRUE,   FALSE,
4964     EL_CHAR('?'),                       -1, -1
4965   },
4966   {
4967     Xalpha_a,                           TRUE,   FALSE,
4968     EL_CHAR('A'),                       -1, -1
4969   },
4970   {
4971     Xalpha_b,                           TRUE,   FALSE,
4972     EL_CHAR('B'),                       -1, -1
4973   },
4974   {
4975     Xalpha_c,                           TRUE,   FALSE,
4976     EL_CHAR('C'),                       -1, -1
4977   },
4978   {
4979     Xalpha_d,                           TRUE,   FALSE,
4980     EL_CHAR('D'),                       -1, -1
4981   },
4982   {
4983     Xalpha_e,                           TRUE,   FALSE,
4984     EL_CHAR('E'),                       -1, -1
4985   },
4986   {
4987     Xalpha_f,                           TRUE,   FALSE,
4988     EL_CHAR('F'),                       -1, -1
4989   },
4990   {
4991     Xalpha_g,                           TRUE,   FALSE,
4992     EL_CHAR('G'),                       -1, -1
4993   },
4994   {
4995     Xalpha_h,                           TRUE,   FALSE,
4996     EL_CHAR('H'),                       -1, -1
4997   },
4998   {
4999     Xalpha_i,                           TRUE,   FALSE,
5000     EL_CHAR('I'),                       -1, -1
5001   },
5002   {
5003     Xalpha_j,                           TRUE,   FALSE,
5004     EL_CHAR('J'),                       -1, -1
5005   },
5006   {
5007     Xalpha_k,                           TRUE,   FALSE,
5008     EL_CHAR('K'),                       -1, -1
5009   },
5010   {
5011     Xalpha_l,                           TRUE,   FALSE,
5012     EL_CHAR('L'),                       -1, -1
5013   },
5014   {
5015     Xalpha_m,                           TRUE,   FALSE,
5016     EL_CHAR('M'),                       -1, -1
5017   },
5018   {
5019     Xalpha_n,                           TRUE,   FALSE,
5020     EL_CHAR('N'),                       -1, -1
5021   },
5022   {
5023     Xalpha_o,                           TRUE,   FALSE,
5024     EL_CHAR('O'),                       -1, -1
5025   },
5026   {
5027     Xalpha_p,                           TRUE,   FALSE,
5028     EL_CHAR('P'),                       -1, -1
5029   },
5030   {
5031     Xalpha_q,                           TRUE,   FALSE,
5032     EL_CHAR('Q'),                       -1, -1
5033   },
5034   {
5035     Xalpha_r,                           TRUE,   FALSE,
5036     EL_CHAR('R'),                       -1, -1
5037   },
5038   {
5039     Xalpha_s,                           TRUE,   FALSE,
5040     EL_CHAR('S'),                       -1, -1
5041   },
5042   {
5043     Xalpha_t,                           TRUE,   FALSE,
5044     EL_CHAR('T'),                       -1, -1
5045   },
5046   {
5047     Xalpha_u,                           TRUE,   FALSE,
5048     EL_CHAR('U'),                       -1, -1
5049   },
5050   {
5051     Xalpha_v,                           TRUE,   FALSE,
5052     EL_CHAR('V'),                       -1, -1
5053   },
5054   {
5055     Xalpha_w,                           TRUE,   FALSE,
5056     EL_CHAR('W'),                       -1, -1
5057   },
5058   {
5059     Xalpha_x,                           TRUE,   FALSE,
5060     EL_CHAR('X'),                       -1, -1
5061   },
5062   {
5063     Xalpha_y,                           TRUE,   FALSE,
5064     EL_CHAR('Y'),                       -1, -1
5065   },
5066   {
5067     Xalpha_z,                           TRUE,   FALSE,
5068     EL_CHAR('Z'),                       -1, -1
5069   },
5070   {
5071     Xalpha_arrow_e,                     TRUE,   FALSE,
5072     EL_CHAR('>'),                       -1, -1
5073   },
5074   {
5075     Xalpha_arrow_w,                     TRUE,   FALSE,
5076     EL_CHAR('<'),                       -1, -1
5077   },
5078   {
5079     Xalpha_copyr,                       TRUE,   FALSE,
5080     EL_CHAR('©'),                       -1, -1
5081   },
5082
5083   {
5084     Xboom_bug,                          FALSE,  FALSE,
5085     EL_BUG,                             ACTION_EXPLODING, -1
5086   },
5087   {
5088     Xboom_bomb,                         FALSE,  FALSE,
5089     EL_BOMB,                            ACTION_EXPLODING, -1
5090   },
5091   {
5092     Xboom_android,                      FALSE,  FALSE,
5093     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5094   },
5095   {
5096     Xboom_1,                            FALSE,  FALSE,
5097     EL_DEFAULT,                         ACTION_EXPLODING, -1
5098   },
5099   {
5100     Xboom_2,                            FALSE,  FALSE,
5101     EL_DEFAULT,                         ACTION_EXPLODING, -1
5102   },
5103   {
5104     Znormal,                            FALSE,  FALSE,
5105     EL_EMPTY,                           -1, -1
5106   },
5107   {
5108     Zdynamite,                          FALSE,  FALSE,
5109     EL_EMPTY,                           -1, -1
5110   },
5111   {
5112     Zplayer,                            FALSE,  FALSE,
5113     EL_EMPTY,                           -1, -1
5114   },
5115   {
5116     ZBORDER,                            FALSE,  FALSE,
5117     EL_EMPTY,                           -1, -1
5118   },
5119
5120   {
5121     -1,                                 FALSE,  FALSE,
5122     -1,                                 -1, -1
5123   }
5124 };
5125
5126 static struct Mapping_EM_to_RND_player
5127 {
5128   int action_em;
5129   int player_nr;
5130
5131   int element_rnd;
5132   int action;
5133   int direction;
5134 }
5135 em_player_mapping_list[] =
5136 {
5137   {
5138     SPR_walk + 0,                       0,
5139     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5140   },
5141   {
5142     SPR_walk + 1,                       0,
5143     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5144   },
5145   {
5146     SPR_walk + 2,                       0,
5147     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5148   },
5149   {
5150     SPR_walk + 3,                       0,
5151     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5152   },
5153   {
5154     SPR_push + 0,                       0,
5155     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5156   },
5157   {
5158     SPR_push + 1,                       0,
5159     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5160   },
5161   {
5162     SPR_push + 2,                       0,
5163     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5164   },
5165   {
5166     SPR_push + 3,                       0,
5167     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5168   },
5169   {
5170     SPR_spray + 0,                      0,
5171     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5172   },
5173   {
5174     SPR_spray + 1,                      0,
5175     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5176   },
5177   {
5178     SPR_spray + 2,                      0,
5179     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5180   },
5181   {
5182     SPR_spray + 3,                      0,
5183     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5184   },
5185   {
5186     SPR_walk + 0,                       1,
5187     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5188   },
5189   {
5190     SPR_walk + 1,                       1,
5191     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5192   },
5193   {
5194     SPR_walk + 2,                       1,
5195     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5196   },
5197   {
5198     SPR_walk + 3,                       1,
5199     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5200   },
5201   {
5202     SPR_push + 0,                       1,
5203     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5204   },
5205   {
5206     SPR_push + 1,                       1,
5207     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5208   },
5209   {
5210     SPR_push + 2,                       1,
5211     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5212   },
5213   {
5214     SPR_push + 3,                       1,
5215     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5216   },
5217   {
5218     SPR_spray + 0,                      1,
5219     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5220   },
5221   {
5222     SPR_spray + 1,                      1,
5223     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5224   },
5225   {
5226     SPR_spray + 2,                      1,
5227     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5228   },
5229   {
5230     SPR_spray + 3,                      1,
5231     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5232   },
5233   {
5234     SPR_still,                          0,
5235     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5236   },
5237   {
5238     SPR_still,                          1,
5239     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5240   },
5241   {
5242     SPR_walk + 0,                       2,
5243     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5244   },
5245   {
5246     SPR_walk + 1,                       2,
5247     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5248   },
5249   {
5250     SPR_walk + 2,                       2,
5251     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5252   },
5253   {
5254     SPR_walk + 3,                       2,
5255     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5256   },
5257   {
5258     SPR_push + 0,                       2,
5259     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5260   },
5261   {
5262     SPR_push + 1,                       2,
5263     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5264   },
5265   {
5266     SPR_push + 2,                       2,
5267     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5268   },
5269   {
5270     SPR_push + 3,                       2,
5271     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5272   },
5273   {
5274     SPR_spray + 0,                      2,
5275     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5276   },
5277   {
5278     SPR_spray + 1,                      2,
5279     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5280   },
5281   {
5282     SPR_spray + 2,                      2,
5283     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5284   },
5285   {
5286     SPR_spray + 3,                      2,
5287     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5288   },
5289   {
5290     SPR_walk + 0,                       3,
5291     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5292   },
5293   {
5294     SPR_walk + 1,                       3,
5295     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5296   },
5297   {
5298     SPR_walk + 2,                       3,
5299     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5300   },
5301   {
5302     SPR_walk + 3,                       3,
5303     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5304   },
5305   {
5306     SPR_push + 0,                       3,
5307     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5308   },
5309   {
5310     SPR_push + 1,                       3,
5311     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5312   },
5313   {
5314     SPR_push + 2,                       3,
5315     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5316   },
5317   {
5318     SPR_push + 3,                       3,
5319     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5320   },
5321   {
5322     SPR_spray + 0,                      3,
5323     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5324   },
5325   {
5326     SPR_spray + 1,                      3,
5327     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5328   },
5329   {
5330     SPR_spray + 2,                      3,
5331     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5332   },
5333   {
5334     SPR_spray + 3,                      3,
5335     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5336   },
5337   {
5338     SPR_still,                          2,
5339     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5340   },
5341   {
5342     SPR_still,                          3,
5343     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5344   },
5345
5346   {
5347     -1,                                 -1,
5348     -1,                                 -1, -1
5349   }
5350 };
5351
5352 int map_element_RND_to_EM(int element_rnd)
5353 {
5354   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5355   static boolean mapping_initialized = FALSE;
5356
5357   if (!mapping_initialized)
5358   {
5359     int i;
5360
5361     /* return "Xalpha_quest" for all undefined elements in mapping array */
5362     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5363       mapping_RND_to_EM[i] = Xalpha_quest;
5364
5365     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5366       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5367         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5368           em_object_mapping_list[i].element_em;
5369
5370     mapping_initialized = TRUE;
5371   }
5372
5373   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5374     return mapping_RND_to_EM[element_rnd];
5375
5376   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5377
5378   return EL_UNKNOWN;
5379 }
5380
5381 int map_element_EM_to_RND(int element_em)
5382 {
5383   static unsigned short mapping_EM_to_RND[TILE_MAX];
5384   static boolean mapping_initialized = FALSE;
5385
5386   if (!mapping_initialized)
5387   {
5388     int i;
5389
5390     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5391     for (i = 0; i < TILE_MAX; i++)
5392       mapping_EM_to_RND[i] = EL_UNKNOWN;
5393
5394     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5395       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5396         em_object_mapping_list[i].element_rnd;
5397
5398     mapping_initialized = TRUE;
5399   }
5400
5401   if (element_em >= 0 && element_em < TILE_MAX)
5402     return mapping_EM_to_RND[element_em];
5403
5404   Error(ERR_WARN, "invalid EM level element %d", element_em);
5405
5406   return EL_UNKNOWN;
5407 }
5408
5409 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5410 {
5411   struct LevelInfo_EM *level_em = level->native_em_level;
5412   struct LEVEL *lev = level_em->lev;
5413   int i, j;
5414
5415   for (i = 0; i < TILE_MAX; i++)
5416     lev->android_array[i] = Xblank;
5417
5418   for (i = 0; i < level->num_android_clone_elements; i++)
5419   {
5420     int element_rnd = level->android_clone_element[i];
5421     int element_em = map_element_RND_to_EM(element_rnd);
5422
5423     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5424       if (em_object_mapping_list[j].element_rnd == element_rnd)
5425         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5426   }
5427 }
5428
5429 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5430 {
5431   struct LevelInfo_EM *level_em = level->native_em_level;
5432   struct LEVEL *lev = level_em->lev;
5433   int i, j;
5434
5435   level->num_android_clone_elements = 0;
5436
5437   for (i = 0; i < TILE_MAX; i++)
5438   {
5439     int element_em = lev->android_array[i];
5440     int element_rnd;
5441     boolean element_found = FALSE;
5442
5443     if (element_em == Xblank)
5444       continue;
5445
5446     element_rnd = map_element_EM_to_RND(element_em);
5447
5448     for (j = 0; j < level->num_android_clone_elements; j++)
5449       if (level->android_clone_element[j] == element_rnd)
5450         element_found = TRUE;
5451
5452     if (!element_found)
5453     {
5454       level->android_clone_element[level->num_android_clone_elements++] =
5455         element_rnd;
5456
5457       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5458         break;
5459     }
5460   }
5461
5462   if (level->num_android_clone_elements == 0)
5463   {
5464     level->num_android_clone_elements = 1;
5465     level->android_clone_element[0] = EL_EMPTY;
5466   }
5467 }
5468
5469 int map_direction_RND_to_EM(int direction)
5470 {
5471   return (direction == MV_UP    ? 0 :
5472           direction == MV_RIGHT ? 1 :
5473           direction == MV_DOWN  ? 2 :
5474           direction == MV_LEFT  ? 3 :
5475           -1);
5476 }
5477
5478 int map_direction_EM_to_RND(int direction)
5479 {
5480   return (direction == 0 ? MV_UP    :
5481           direction == 1 ? MV_RIGHT :
5482           direction == 2 ? MV_DOWN  :
5483           direction == 3 ? MV_LEFT  :
5484           MV_NONE);
5485 }
5486
5487 int get_next_element(int element)
5488 {
5489   switch (element)
5490   {
5491     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5492     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5493     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5494     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5495     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5496     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5497     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5498     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5499     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5500     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5501     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5502
5503     default:                            return element;
5504   }
5505 }
5506
5507 #if 0
5508 int el_act_dir2img(int element, int action, int direction)
5509 {
5510   element = GFX_ELEMENT(element);
5511
5512   if (direction == MV_NONE)
5513     return element_info[element].graphic[action];
5514
5515   direction = MV_DIR_TO_BIT(direction);
5516
5517   return element_info[element].direction_graphic[action][direction];
5518 }
5519 #else
5520 int el_act_dir2img(int element, int action, int direction)
5521 {
5522   element = GFX_ELEMENT(element);
5523   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5524
5525   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5526   return element_info[element].direction_graphic[action][direction];
5527 }
5528 #endif
5529
5530 #if 0
5531 static int el_act_dir2crm(int element, int action, int direction)
5532 {
5533   element = GFX_ELEMENT(element);
5534
5535   if (direction == MV_NONE)
5536     return element_info[element].crumbled[action];
5537
5538   direction = MV_DIR_TO_BIT(direction);
5539
5540   return element_info[element].direction_crumbled[action][direction];
5541 }
5542 #else
5543 static int el_act_dir2crm(int element, int action, int direction)
5544 {
5545   element = GFX_ELEMENT(element);
5546   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5547
5548   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5549   return element_info[element].direction_crumbled[action][direction];
5550 }
5551 #endif
5552
5553 int el_act2img(int element, int action)
5554 {
5555   element = GFX_ELEMENT(element);
5556
5557   return element_info[element].graphic[action];
5558 }
5559
5560 int el_act2crm(int element, int action)
5561 {
5562   element = GFX_ELEMENT(element);
5563
5564   return element_info[element].crumbled[action];
5565 }
5566
5567 int el_dir2img(int element, int direction)
5568 {
5569   element = GFX_ELEMENT(element);
5570
5571   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5572 }
5573
5574 int el2baseimg(int element)
5575 {
5576   return element_info[element].graphic[ACTION_DEFAULT];
5577 }
5578
5579 int el2img(int element)
5580 {
5581   element = GFX_ELEMENT(element);
5582
5583   return element_info[element].graphic[ACTION_DEFAULT];
5584 }
5585
5586 int el2edimg(int element)
5587 {
5588   element = GFX_ELEMENT(element);
5589
5590   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5591 }
5592
5593 int el2preimg(int element)
5594 {
5595   element = GFX_ELEMENT(element);
5596
5597   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5598 }
5599
5600 int font2baseimg(int font_nr)
5601 {
5602   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5603 }
5604
5605 int getBeltNrFromBeltElement(int element)
5606 {
5607   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5608           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5609           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5610 }
5611
5612 int getBeltNrFromBeltActiveElement(int element)
5613 {
5614   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5615           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5616           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5617 }
5618
5619 int getBeltNrFromBeltSwitchElement(int element)
5620 {
5621   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5622           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5623           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5624 }
5625
5626 int getBeltDirNrFromBeltElement(int element)
5627 {
5628   static int belt_base_element[4] =
5629   {
5630     EL_CONVEYOR_BELT_1_LEFT,
5631     EL_CONVEYOR_BELT_2_LEFT,
5632     EL_CONVEYOR_BELT_3_LEFT,
5633     EL_CONVEYOR_BELT_4_LEFT
5634   };
5635
5636   int belt_nr = getBeltNrFromBeltElement(element);
5637   int belt_dir_nr = element - belt_base_element[belt_nr];
5638
5639   return (belt_dir_nr % 3);
5640 }
5641
5642 int getBeltDirNrFromBeltSwitchElement(int element)
5643 {
5644   static int belt_base_element[4] =
5645   {
5646     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5647     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5648     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5649     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5650   };
5651
5652   int belt_nr = getBeltNrFromBeltSwitchElement(element);
5653   int belt_dir_nr = element - belt_base_element[belt_nr];
5654
5655   return (belt_dir_nr % 3);
5656 }
5657
5658 int getBeltDirFromBeltElement(int element)
5659 {
5660   static int belt_move_dir[3] =
5661   {
5662     MV_LEFT,
5663     MV_NONE,
5664     MV_RIGHT
5665   };
5666
5667   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5668
5669   return belt_move_dir[belt_dir_nr];
5670 }
5671
5672 int getBeltDirFromBeltSwitchElement(int element)
5673 {
5674   static int belt_move_dir[3] =
5675   {
5676     MV_LEFT,
5677     MV_NONE,
5678     MV_RIGHT
5679   };
5680
5681   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5682
5683   return belt_move_dir[belt_dir_nr];
5684 }
5685
5686 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5687 {
5688   static int belt_base_element[4] =
5689   {
5690     EL_CONVEYOR_BELT_1_LEFT,
5691     EL_CONVEYOR_BELT_2_LEFT,
5692     EL_CONVEYOR_BELT_3_LEFT,
5693     EL_CONVEYOR_BELT_4_LEFT
5694   };
5695   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5696
5697   return belt_base_element[belt_nr] + belt_dir_nr;
5698 }
5699
5700 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5701 {
5702   static int belt_base_element[4] =
5703   {
5704     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5705     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5706     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5707     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5708   };
5709   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5710
5711   return belt_base_element[belt_nr] + belt_dir_nr;
5712 }
5713
5714 int getNumActivePlayers_EM()
5715 {
5716   int num_players = 0;
5717   int i;
5718
5719   if (!tape.playing)
5720     return -1;
5721
5722   for (i = 0; i < MAX_PLAYERS; i++)
5723     if (tape.player_participates[i])
5724       num_players++;
5725
5726   return num_players;
5727 }
5728
5729 int getGameFrameDelay_EM(int native_em_game_frame_delay)
5730 {
5731   int game_frame_delay_value;
5732
5733   game_frame_delay_value =
5734     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
5735      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
5736      GameFrameDelay);
5737
5738   if (tape.playing && tape.warp_forward && !tape.pausing)
5739     game_frame_delay_value = 0;
5740
5741   return game_frame_delay_value;
5742 }
5743
5744 unsigned int InitRND(long seed)
5745 {
5746   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5747     return InitEngineRandom_EM(seed);
5748   else
5749     return InitEngineRandom_RND(seed);
5750 }
5751
5752 #if 1
5753 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5754 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5755 #endif
5756
5757 void ResetGfxAnimation_EM(int x, int y, int tile)
5758 {
5759   GfxFrame[x][y] = 0;
5760 }
5761
5762 void getGraphicSourceObjectExt_EM(int tile, int frame_em,
5763                                   Bitmap **src_bitmap, int *src_x, int *src_y,
5764                                   int x, int y)
5765 {
5766   int element         = object_mapping[tile].element_rnd;
5767   int action          = object_mapping[tile].action;
5768   int direction       = object_mapping[tile].direction;
5769   boolean is_backside = object_mapping[tile].is_backside;
5770   boolean action_removing = (action == ACTION_DIGGING ||
5771                              action == ACTION_SNAPPING ||
5772                              action == ACTION_COLLECTING);
5773   int effective_element = (frame_em > 0 ? element :
5774                            is_backside ? EL_EMPTY :
5775                            action_removing ? EL_EMPTY :
5776                            element);
5777   int graphic = (direction == MV_NONE ?
5778                  el_act2img(effective_element, action) :
5779                  el_act_dir2img(effective_element, action, direction));
5780   struct GraphicInfo *g = &graphic_info[graphic];
5781   int sync_frame;
5782
5783   if (graphic_info[graphic].anim_global_sync)
5784     sync_frame = FrameCounter;
5785   else
5786     sync_frame = 7 - frame_em;
5787
5788   SetRandomAnimationValue(x, y);
5789
5790   int frame = getAnimationFrame(g->anim_frames,
5791                                 g->anim_delay,
5792                                 g->anim_mode,
5793                                 g->anim_start_frame,
5794                                 sync_frame);
5795
5796   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5797 }
5798
5799 void getGraphicSourcePlayerExt_EM(int player_nr, int anim, int frame_em,
5800                                   Bitmap **src_bitmap, int *src_x, int *src_y)
5801 {
5802   int element   = player_mapping[player_nr][anim].element_rnd;
5803   int action    = player_mapping[player_nr][anim].action;
5804   int direction = player_mapping[player_nr][anim].direction;
5805   int graphic = (direction == MV_NONE ?
5806                  el_act2img(element, action) :
5807                  el_act_dir2img(element, action, direction));
5808   struct GraphicInfo *g = &graphic_info[graphic];
5809   int sync_frame;
5810
5811   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
5812
5813   stored_player[player_nr].StepFrame = 7 - frame_em;
5814
5815   sync_frame = stored_player[player_nr].Frame;
5816
5817 #if 0
5818   printf("::: %d: %d, %d [%d]\n",
5819          player_nr,
5820          stored_player[player_nr].Frame,
5821          stored_player[player_nr].StepFrame,
5822          FrameCounter);
5823 #endif
5824
5825   int frame = getAnimationFrame(g->anim_frames,
5826                                 g->anim_delay,
5827                                 g->anim_mode,
5828                                 g->anim_start_frame,
5829                                 sync_frame);
5830
5831   getGraphicSourceExt(graphic, frame, src_bitmap, src_x, src_y, FALSE);
5832 }
5833
5834 void InitGraphicInfo_EM(void)
5835 {
5836 #if 0
5837   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
5838   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
5839 #endif
5840   int i, j, p;
5841
5842 #if DEBUG_EM_GFX
5843   int num_em_gfx_errors = 0;
5844
5845   if (graphic_info_em_object[0][0].bitmap == NULL)
5846   {
5847     /* EM graphics not yet initialized in em_open_all() */
5848
5849     return;
5850   }
5851
5852   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
5853 #endif
5854
5855   /* always start with reliable default values */
5856   for (i = 0; i < TILE_MAX; i++)
5857   {
5858     object_mapping[i].element_rnd = EL_UNKNOWN;
5859     object_mapping[i].is_backside = FALSE;
5860     object_mapping[i].action = ACTION_DEFAULT;
5861     object_mapping[i].direction = MV_NONE;
5862   }
5863
5864   /* always start with reliable default values */
5865   for (p = 0; p < MAX_PLAYERS; p++)
5866   {
5867     for (i = 0; i < SPR_MAX; i++)
5868     {
5869       player_mapping[p][i].element_rnd = EL_UNKNOWN;
5870       player_mapping[p][i].action = ACTION_DEFAULT;
5871       player_mapping[p][i].direction = MV_NONE;
5872     }
5873   }
5874
5875   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5876   {
5877     int e = em_object_mapping_list[i].element_em;
5878
5879     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
5880     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
5881
5882     if (em_object_mapping_list[i].action != -1)
5883       object_mapping[e].action = em_object_mapping_list[i].action;
5884
5885     if (em_object_mapping_list[i].direction != -1)
5886       object_mapping[e].direction =
5887         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
5888   }
5889
5890   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
5891   {
5892     int a = em_player_mapping_list[i].action_em;
5893     int p = em_player_mapping_list[i].player_nr;
5894
5895     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
5896
5897     if (em_player_mapping_list[i].action != -1)
5898       player_mapping[p][a].action = em_player_mapping_list[i].action;
5899
5900     if (em_player_mapping_list[i].direction != -1)
5901       player_mapping[p][a].direction =
5902         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
5903   }
5904
5905   for (i = 0; i < TILE_MAX; i++)
5906   {
5907     int element = object_mapping[i].element_rnd;
5908     int action = object_mapping[i].action;
5909     int direction = object_mapping[i].direction;
5910     boolean is_backside = object_mapping[i].is_backside;
5911     boolean action_removing = (action == ACTION_DIGGING ||
5912                                action == ACTION_SNAPPING ||
5913                                action == ACTION_COLLECTING);
5914     boolean action_exploding = ((action == ACTION_EXPLODING ||
5915                                  action == ACTION_SMASHED_BY_ROCK ||
5916                                  action == ACTION_SMASHED_BY_SPRING) &&
5917                                 element != EL_DIAMOND);
5918     boolean action_active = (action == ACTION_ACTIVE);
5919     boolean action_other = (action == ACTION_OTHER);
5920
5921     for (j = 0; j < 8; j++)
5922     {
5923       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
5924                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
5925                                j < 7 ? element :
5926                                i == Xdrip_stretch ? element :
5927                                i == Xdrip_stretchB ? element :
5928                                i == Ydrip_s1 ? element :
5929                                i == Ydrip_s1B ? element :
5930                                i == Xball_1B ? element :
5931                                i == Xball_2 ? element :
5932                                i == Xball_2B ? element :
5933                                i == Yball_eat ? element :
5934                                i == Ykey_1_eat ? element :
5935                                i == Ykey_2_eat ? element :
5936                                i == Ykey_3_eat ? element :
5937                                i == Ykey_4_eat ? element :
5938                                i == Ykey_5_eat ? element :
5939                                i == Ykey_6_eat ? element :
5940                                i == Ykey_7_eat ? element :
5941                                i == Ykey_8_eat ? element :
5942                                i == Ylenses_eat ? element :
5943                                i == Ymagnify_eat ? element :
5944                                i == Ygrass_eat ? element :
5945                                i == Ydirt_eat ? element :
5946                                i == Yemerald_stone ? EL_EMERALD :
5947                                i == Ydiamond_stone ? EL_ROCK :
5948                                i == Xsand_stonein_1 ? element :
5949                                i == Xsand_stonein_2 ? element :
5950                                i == Xsand_stonein_3 ? element :
5951                                i == Xsand_stonein_4 ? element :
5952                                is_backside ? EL_EMPTY :
5953                                action_removing ? EL_EMPTY :
5954                                element);
5955       int effective_action = (j < 7 ? action :
5956                               i == Xdrip_stretch ? action :
5957                               i == Xdrip_stretchB ? action :
5958                               i == Ydrip_s1 ? action :
5959                               i == Ydrip_s1B ? action :
5960                               i == Xball_1B ? action :
5961                               i == Xball_2 ? action :
5962                               i == Xball_2B ? action :
5963                               i == Yball_eat ? action :
5964                               i == Ykey_1_eat ? action :
5965                               i == Ykey_2_eat ? action :
5966                               i == Ykey_3_eat ? action :
5967                               i == Ykey_4_eat ? action :
5968                               i == Ykey_5_eat ? action :
5969                               i == Ykey_6_eat ? action :
5970                               i == Ykey_7_eat ? action :
5971                               i == Ykey_8_eat ? action :
5972                               i == Ylenses_eat ? action :
5973                               i == Ymagnify_eat ? action :
5974                               i == Ygrass_eat ? action :
5975                               i == Ydirt_eat ? action :
5976                               i == Xsand_stonein_1 ? action :
5977                               i == Xsand_stonein_2 ? action :
5978                               i == Xsand_stonein_3 ? action :
5979                               i == Xsand_stonein_4 ? action :
5980                               i == Xsand_stoneout_1 ? action :
5981                               i == Xsand_stoneout_2 ? action :
5982                               i == Xboom_android ? ACTION_EXPLODING :
5983                               action_exploding ? ACTION_EXPLODING :
5984                               action_active ? action :
5985                               action_other ? action :
5986                               ACTION_DEFAULT);
5987       int graphic = (el_act_dir2img(effective_element, effective_action,
5988                                     direction));
5989       int crumbled = (el_act_dir2crm(effective_element, effective_action,
5990                                      direction));
5991       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
5992       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
5993       boolean has_action_graphics = (graphic != base_graphic);
5994       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
5995       struct GraphicInfo *g = &graphic_info[graphic];
5996       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
5997       Bitmap *src_bitmap;
5998       int src_x, src_y;
5999       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6000       boolean special_animation = (action != ACTION_DEFAULT &&
6001                                    g->anim_frames == 3 &&
6002                                    g->anim_delay == 2 &&
6003                                    g->anim_mode & ANIM_LINEAR);
6004       int sync_frame = (i == Xdrip_stretch ? 7 :
6005                         i == Xdrip_stretchB ? 7 :
6006                         i == Ydrip_s2 ? j + 8 :
6007                         i == Ydrip_s2B ? j + 8 :
6008                         i == Xacid_1 ? 0 :
6009                         i == Xacid_2 ? 10 :
6010                         i == Xacid_3 ? 20 :
6011                         i == Xacid_4 ? 30 :
6012                         i == Xacid_5 ? 40 :
6013                         i == Xacid_6 ? 50 :
6014                         i == Xacid_7 ? 60 :
6015                         i == Xacid_8 ? 70 :
6016                         i == Xfake_acid_1 ? 0 :
6017                         i == Xfake_acid_2 ? 10 :
6018                         i == Xfake_acid_3 ? 20 :
6019                         i == Xfake_acid_4 ? 30 :
6020                         i == Xfake_acid_5 ? 40 :
6021                         i == Xfake_acid_6 ? 50 :
6022                         i == Xfake_acid_7 ? 60 :
6023                         i == Xfake_acid_8 ? 70 :
6024                         i == Xball_2 ? 7 :
6025                         i == Xball_2B ? j + 8 :
6026                         i == Yball_eat ? j + 1 :
6027                         i == Ykey_1_eat ? j + 1 :
6028                         i == Ykey_2_eat ? j + 1 :
6029                         i == Ykey_3_eat ? j + 1 :
6030                         i == Ykey_4_eat ? j + 1 :
6031                         i == Ykey_5_eat ? j + 1 :
6032                         i == Ykey_6_eat ? j + 1 :
6033                         i == Ykey_7_eat ? j + 1 :
6034                         i == Ykey_8_eat ? j + 1 :
6035                         i == Ylenses_eat ? j + 1 :
6036                         i == Ymagnify_eat ? j + 1 :
6037                         i == Ygrass_eat ? j + 1 :
6038                         i == Ydirt_eat ? j + 1 :
6039                         i == Xamoeba_1 ? 0 :
6040                         i == Xamoeba_2 ? 1 :
6041                         i == Xamoeba_3 ? 2 :
6042                         i == Xamoeba_4 ? 3 :
6043                         i == Xamoeba_5 ? 0 :
6044                         i == Xamoeba_6 ? 1 :
6045                         i == Xamoeba_7 ? 2 :
6046                         i == Xamoeba_8 ? 3 :
6047                         i == Xexit_2 ? j + 8 :
6048                         i == Xexit_3 ? j + 16 :
6049                         i == Xdynamite_1 ? 0 :
6050                         i == Xdynamite_2 ? 8 :
6051                         i == Xdynamite_3 ? 16 :
6052                         i == Xdynamite_4 ? 24 :
6053                         i == Xsand_stonein_1 ? j + 1 :
6054                         i == Xsand_stonein_2 ? j + 9 :
6055                         i == Xsand_stonein_3 ? j + 17 :
6056                         i == Xsand_stonein_4 ? j + 25 :
6057                         i == Xsand_stoneout_1 && j == 0 ? 0 :
6058                         i == Xsand_stoneout_1 && j == 1 ? 0 :
6059                         i == Xsand_stoneout_1 && j == 2 ? 1 :
6060                         i == Xsand_stoneout_1 && j == 3 ? 2 :
6061                         i == Xsand_stoneout_1 && j == 4 ? 2 :
6062                         i == Xsand_stoneout_1 && j == 5 ? 3 :
6063                         i == Xsand_stoneout_1 && j == 6 ? 4 :
6064                         i == Xsand_stoneout_1 && j == 7 ? 4 :
6065                         i == Xsand_stoneout_2 && j == 0 ? 5 :
6066                         i == Xsand_stoneout_2 && j == 1 ? 6 :
6067                         i == Xsand_stoneout_2 && j == 2 ? 7 :
6068                         i == Xsand_stoneout_2 && j == 3 ? 8 :
6069                         i == Xsand_stoneout_2 && j == 4 ? 9 :
6070                         i == Xsand_stoneout_2 && j == 5 ? 11 :
6071                         i == Xsand_stoneout_2 && j == 6 ? 13 :
6072                         i == Xsand_stoneout_2 && j == 7 ? 15 :
6073                         i == Xboom_bug && j == 1 ? 2 :
6074                         i == Xboom_bug && j == 2 ? 2 :
6075                         i == Xboom_bug && j == 3 ? 4 :
6076                         i == Xboom_bug && j == 4 ? 4 :
6077                         i == Xboom_bug && j == 5 ? 2 :
6078                         i == Xboom_bug && j == 6 ? 2 :
6079                         i == Xboom_bug && j == 7 ? 0 :
6080                         i == Xboom_bomb && j == 1 ? 2 :
6081                         i == Xboom_bomb && j == 2 ? 2 :
6082                         i == Xboom_bomb && j == 3 ? 4 :
6083                         i == Xboom_bomb && j == 4 ? 4 :
6084                         i == Xboom_bomb && j == 5 ? 2 :
6085                         i == Xboom_bomb && j == 6 ? 2 :
6086                         i == Xboom_bomb && j == 7 ? 0 :
6087                         i == Xboom_android && j == 7 ? 6 :
6088                         i == Xboom_1 && j == 1 ? 2 :
6089                         i == Xboom_1 && j == 2 ? 2 :
6090                         i == Xboom_1 && j == 3 ? 4 :
6091                         i == Xboom_1 && j == 4 ? 4 :
6092                         i == Xboom_1 && j == 5 ? 6 :
6093                         i == Xboom_1 && j == 6 ? 6 :
6094                         i == Xboom_1 && j == 7 ? 8 :
6095                         i == Xboom_2 && j == 0 ? 8 :
6096                         i == Xboom_2 && j == 1 ? 8 :
6097                         i == Xboom_2 && j == 2 ? 10 :
6098                         i == Xboom_2 && j == 3 ? 10 :
6099                         i == Xboom_2 && j == 4 ? 10 :
6100                         i == Xboom_2 && j == 5 ? 12 :
6101                         i == Xboom_2 && j == 6 ? 12 :
6102                         i == Xboom_2 && j == 7 ? 12 :
6103                         special_animation && j == 4 ? 3 :
6104                         effective_action != action ? 0 :
6105                         j);
6106
6107 #if DEBUG_EM_GFX
6108       Bitmap *debug_bitmap = g_em->bitmap;
6109       int debug_src_x = g_em->src_x;
6110       int debug_src_y = g_em->src_y;
6111 #endif
6112
6113       int frame = getAnimationFrame(g->anim_frames,
6114                                     g->anim_delay,
6115                                     g->anim_mode,
6116                                     g->anim_start_frame,
6117                                     sync_frame);
6118
6119       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6120                           g->double_movement && is_backside);
6121
6122       g_em->bitmap = src_bitmap;
6123       g_em->src_x = src_x;
6124       g_em->src_y = src_y;
6125       g_em->src_offset_x = 0;
6126       g_em->src_offset_y = 0;
6127       g_em->dst_offset_x = 0;
6128       g_em->dst_offset_y = 0;
6129       g_em->width  = TILEX;
6130       g_em->height = TILEY;
6131
6132       g_em->crumbled_bitmap = NULL;
6133       g_em->crumbled_src_x = 0;
6134       g_em->crumbled_src_y = 0;
6135       g_em->crumbled_border_size = 0;
6136
6137       g_em->has_crumbled_graphics = FALSE;
6138       g_em->preserve_background = FALSE;
6139
6140 #if 0
6141       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6142         printf("::: empty crumbled: %d [%s], %d, %d\n",
6143                effective_element, element_info[effective_element].token_name,
6144                effective_action, direction);
6145 #endif
6146
6147       /* if element can be crumbled, but certain action graphics are just empty
6148          space (like snapping sand with the original R'n'D graphics), do not
6149          treat these empty space graphics as crumbled graphics in EMC engine */
6150       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6151       {
6152         getGraphicSource(crumbled, frame, &src_bitmap, &src_x, &src_y);
6153
6154         g_em->has_crumbled_graphics = TRUE;
6155         g_em->crumbled_bitmap = src_bitmap;
6156         g_em->crumbled_src_x = src_x;
6157         g_em->crumbled_src_y = src_y;
6158         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6159       }
6160
6161 #if 0
6162       if (element == EL_ROCK &&
6163           effective_action == ACTION_FILLING)
6164         printf("::: has_action_graphics == %d\n", has_action_graphics);
6165 #endif
6166
6167       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6168                                    effective_action == ACTION_MOVING  ||
6169                                    effective_action == ACTION_PUSHING ||
6170                                    effective_action == ACTION_EATING)) ||
6171           (!has_action_graphics && (effective_action == ACTION_FILLING ||
6172                                     effective_action == ACTION_EMPTYING)))
6173       {
6174         int move_dir =
6175           (effective_action == ACTION_FALLING ||
6176            effective_action == ACTION_FILLING ||
6177            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6178         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6179         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
6180         int num_steps = (i == Ydrip_s1  ? 16 :
6181                          i == Ydrip_s1B ? 16 :
6182                          i == Ydrip_s2  ? 16 :
6183                          i == Ydrip_s2B ? 16 :
6184                          i == Xsand_stonein_1 ? 32 :
6185                          i == Xsand_stonein_2 ? 32 :
6186                          i == Xsand_stonein_3 ? 32 :
6187                          i == Xsand_stonein_4 ? 32 :
6188                          i == Xsand_stoneout_1 ? 16 :
6189                          i == Xsand_stoneout_2 ? 16 : 8);
6190         int cx = ABS(dx) * (TILEX / num_steps);
6191         int cy = ABS(dy) * (TILEY / num_steps);
6192         int step_frame = (i == Ydrip_s2         ? j + 8 :
6193                           i == Ydrip_s2B        ? j + 8 :
6194                           i == Xsand_stonein_2  ? j + 8 :
6195                           i == Xsand_stonein_3  ? j + 16 :
6196                           i == Xsand_stonein_4  ? j + 24 :
6197                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6198         int step = (is_backside ? step_frame : num_steps - step_frame);
6199
6200         if (is_backside)        /* tile where movement starts */
6201         {
6202           if (dx < 0 || dy < 0)
6203           {
6204             g_em->src_offset_x = cx * step;
6205             g_em->src_offset_y = cy * step;
6206           }
6207           else
6208           {
6209             g_em->dst_offset_x = cx * step;
6210             g_em->dst_offset_y = cy * step;
6211           }
6212         }
6213         else                    /* tile where movement ends */
6214         {
6215           if (dx < 0 || dy < 0)
6216           {
6217             g_em->dst_offset_x = cx * step;
6218             g_em->dst_offset_y = cy * step;
6219           }
6220           else
6221           {
6222             g_em->src_offset_x = cx * step;
6223             g_em->src_offset_y = cy * step;
6224           }
6225         }
6226
6227         g_em->width  = TILEX - cx * step;
6228         g_em->height = TILEY - cy * step;
6229       }
6230
6231       /* create unique graphic identifier to decide if tile must be redrawn */
6232       /* bit 31 - 16 (16 bit): EM style graphic
6233          bit 15 - 12 ( 4 bit): EM style frame
6234          bit 11 -  6 ( 6 bit): graphic width
6235          bit  5 -  0 ( 6 bit): graphic height */
6236       g_em->unique_identifier =
6237         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6238
6239 #if DEBUG_EM_GFX
6240
6241       /* skip check for EMC elements not contained in original EMC artwork */
6242       if (element == EL_EMC_FAKE_ACID)
6243         continue;
6244
6245       if (g_em->bitmap != debug_bitmap ||
6246           g_em->src_x != debug_src_x ||
6247           g_em->src_y != debug_src_y ||
6248           g_em->src_offset_x != 0 ||
6249           g_em->src_offset_y != 0 ||
6250           g_em->dst_offset_x != 0 ||
6251           g_em->dst_offset_y != 0 ||
6252           g_em->width != TILEX ||
6253           g_em->height != TILEY)
6254       {
6255         static int last_i = -1;
6256
6257         if (i != last_i)
6258         {
6259           printf("\n");
6260           last_i = i;
6261         }
6262
6263         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6264                i, element, element_info[element].token_name,
6265                element_action_info[effective_action].suffix, direction);
6266
6267         if (element != effective_element)
6268           printf(" [%d ('%s')]",
6269                  effective_element,
6270                  element_info[effective_element].token_name);
6271
6272         printf("\n");
6273
6274         if (g_em->bitmap != debug_bitmap)
6275           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6276                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6277
6278         if (g_em->src_x != debug_src_x ||
6279             g_em->src_y != debug_src_y)
6280           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6281                  j, (is_backside ? 'B' : 'F'),
6282                  g_em->src_x, g_em->src_y,
6283                  g_em->src_x / 32, g_em->src_y / 32,
6284                  debug_src_x, debug_src_y,
6285                  debug_src_x / 32, debug_src_y / 32);
6286
6287         if (g_em->src_offset_x != 0 ||
6288             g_em->src_offset_y != 0 ||
6289             g_em->dst_offset_x != 0 ||
6290             g_em->dst_offset_y != 0)
6291           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6292                  j, is_backside,
6293                  g_em->src_offset_x, g_em->src_offset_y,
6294                  g_em->dst_offset_x, g_em->dst_offset_y);
6295
6296         if (g_em->width != TILEX ||
6297             g_em->height != TILEY)
6298           printf("    %d (%d): size %d,%d should be %d,%d\n",
6299                  j, is_backside,
6300                  g_em->width, g_em->height, TILEX, TILEY);
6301
6302         num_em_gfx_errors++;
6303       }
6304 #endif
6305
6306     }
6307   }
6308
6309   for (i = 0; i < TILE_MAX; i++)
6310   {
6311     for (j = 0; j < 8; j++)
6312     {
6313       int element = object_mapping[i].element_rnd;
6314       int action = object_mapping[i].action;
6315       int direction = object_mapping[i].direction;
6316       boolean is_backside = object_mapping[i].is_backside;
6317       int graphic_action  = el_act_dir2img(element, action, direction);
6318       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6319
6320       if ((action == ACTION_SMASHED_BY_ROCK ||
6321            action == ACTION_SMASHED_BY_SPRING ||
6322            action == ACTION_EATING) &&
6323           graphic_action == graphic_default)
6324       {
6325         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6326                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6327                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6328                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6329                  Xspring);
6330
6331         /* no separate animation for "smashed by rock" -- use rock instead */
6332         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6333         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6334
6335         g_em->bitmap            = g_xx->bitmap;
6336         g_em->src_x             = g_xx->src_x;
6337         g_em->src_y             = g_xx->src_y;
6338         g_em->src_offset_x      = g_xx->src_offset_x;
6339         g_em->src_offset_y      = g_xx->src_offset_y;
6340         g_em->dst_offset_x      = g_xx->dst_offset_x;
6341         g_em->dst_offset_y      = g_xx->dst_offset_y;
6342         g_em->width             = g_xx->width;
6343         g_em->height            = g_xx->height;
6344         g_em->unique_identifier = g_xx->unique_identifier;
6345
6346         if (!is_backside)
6347           g_em->preserve_background = TRUE;
6348       }
6349     }
6350   }
6351
6352   for (p = 0; p < MAX_PLAYERS; p++)
6353   {
6354     for (i = 0; i < SPR_MAX; i++)
6355     {
6356       int element = player_mapping[p][i].element_rnd;
6357       int action = player_mapping[p][i].action;
6358       int direction = player_mapping[p][i].direction;
6359
6360       for (j = 0; j < 8; j++)
6361       {
6362         int effective_element = element;
6363         int effective_action = action;
6364         int graphic = (direction == MV_NONE ?
6365                        el_act2img(effective_element, effective_action) :
6366                        el_act_dir2img(effective_element, effective_action,
6367                                       direction));
6368         struct GraphicInfo *g = &graphic_info[graphic];
6369         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6370         Bitmap *src_bitmap;
6371         int src_x, src_y;
6372         int sync_frame = j;
6373
6374 #if DEBUG_EM_GFX
6375         Bitmap *debug_bitmap = g_em->bitmap;
6376         int debug_src_x = g_em->src_x;
6377         int debug_src_y = g_em->src_y;
6378 #endif
6379
6380         int frame = getAnimationFrame(g->anim_frames,
6381                                       g->anim_delay,
6382                                       g->anim_mode,
6383                                       g->anim_start_frame,
6384                                       sync_frame);
6385
6386         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
6387
6388         g_em->bitmap = src_bitmap;
6389         g_em->src_x = src_x;
6390         g_em->src_y = src_y;
6391         g_em->src_offset_x = 0;
6392         g_em->src_offset_y = 0;
6393         g_em->dst_offset_x = 0;
6394         g_em->dst_offset_y = 0;
6395         g_em->width  = TILEX;
6396         g_em->height = TILEY;
6397
6398 #if DEBUG_EM_GFX
6399
6400         /* skip check for EMC elements not contained in original EMC artwork */
6401         if (element == EL_PLAYER_3 ||
6402             element == EL_PLAYER_4)
6403           continue;
6404
6405         if (g_em->bitmap != debug_bitmap ||
6406             g_em->src_x != debug_src_x ||
6407             g_em->src_y != debug_src_y)
6408         {
6409           static int last_i = -1;
6410
6411           if (i != last_i)
6412           {
6413             printf("\n");
6414             last_i = i;
6415           }
6416
6417           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
6418                  p, i, element, element_info[element].token_name,
6419                  element_action_info[effective_action].suffix, direction);
6420
6421           if (element != effective_element)
6422             printf(" [%d ('%s')]",
6423                    effective_element,
6424                    element_info[effective_element].token_name);
6425
6426           printf("\n");
6427
6428           if (g_em->bitmap != debug_bitmap)
6429             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
6430                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
6431
6432           if (g_em->src_x != debug_src_x ||
6433               g_em->src_y != debug_src_y)
6434             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6435                    j,
6436                    g_em->src_x, g_em->src_y,
6437                    g_em->src_x / 32, g_em->src_y / 32,
6438                    debug_src_x, debug_src_y,
6439                    debug_src_x / 32, debug_src_y / 32);
6440
6441           num_em_gfx_errors++;
6442         }
6443 #endif
6444
6445       }
6446     }
6447   }
6448
6449 #if DEBUG_EM_GFX
6450   printf("\n");
6451   printf("::: [%d errors found]\n", num_em_gfx_errors);
6452
6453   exit(0);
6454 #endif
6455 }
6456
6457 void PlayMenuSound()
6458 {
6459   int sound = menu.sound[game_status];
6460
6461   if (sound == SND_UNDEFINED)
6462     return;
6463
6464   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6465       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6466     return;
6467
6468   if (IS_LOOP_SOUND(sound))
6469     PlaySoundLoop(sound);
6470   else
6471     PlaySound(sound);
6472 }
6473
6474 void PlayMenuSoundStereo(int sound, int stereo_position)
6475 {
6476   if (sound == SND_UNDEFINED)
6477     return;
6478
6479   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6480       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6481     return;
6482
6483   if (IS_LOOP_SOUND(sound))
6484     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
6485   else
6486     PlaySoundStereo(sound, stereo_position);
6487 }
6488
6489 void PlayMenuSoundIfLoop()
6490 {
6491   int sound = menu.sound[game_status];
6492
6493   if (sound == SND_UNDEFINED)
6494     return;
6495
6496   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
6497       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
6498     return;
6499
6500   if (IS_LOOP_SOUND(sound))
6501     PlaySoundLoop(sound);
6502 }
6503
6504 void PlayMenuMusic()
6505 {
6506   int music = menu.music[game_status];
6507
6508   if (music == MUS_UNDEFINED)
6509     return;
6510
6511   if (!setup.sound_music)
6512     return;
6513
6514   PlayMusic(music);
6515 }
6516
6517 void PlaySoundActivating()
6518 {
6519 #if 0
6520   PlaySound(SND_MENU_ITEM_ACTIVATING);
6521 #endif
6522 }
6523
6524 void PlaySoundSelecting()
6525 {
6526 #if 0
6527   PlaySound(SND_MENU_ITEM_SELECTING);
6528 #endif
6529 }
6530
6531 void ToggleFullscreenIfNeeded()
6532 {
6533   boolean change_fullscreen = (setup.fullscreen !=
6534                                video.fullscreen_enabled);
6535   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
6536                                     !strEqual(setup.fullscreen_mode,
6537                                               video.fullscreen_mode_current));
6538
6539   if (!video.fullscreen_available)
6540     return;
6541
6542 #if 1
6543   if (change_fullscreen || change_fullscreen_mode)
6544 #else
6545   if (setup.fullscreen != video.fullscreen_enabled ||
6546       setup.fullscreen_mode != video.fullscreen_mode_current)
6547 #endif
6548   {
6549     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
6550
6551     /* save backbuffer content which gets lost when toggling fullscreen mode */
6552     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6553
6554 #if 1
6555     if (change_fullscreen_mode)
6556 #else
6557     if (setup.fullscreen && video.fullscreen_enabled)
6558 #endif
6559     {
6560       /* keep fullscreen, but change fullscreen mode (screen resolution) */
6561 #if 1
6562       /* (this is now set in sdl.c) */
6563 #else
6564       video.fullscreen_mode_current = setup.fullscreen_mode;
6565 #endif
6566       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
6567     }
6568
6569     /* toggle fullscreen */
6570     ChangeVideoModeIfNeeded(setup.fullscreen);
6571
6572     setup.fullscreen = video.fullscreen_enabled;
6573
6574     /* restore backbuffer content from temporary backbuffer backup bitmap */
6575     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6576
6577     FreeBitmap(tmp_backbuffer);
6578
6579 #if 1
6580     /* update visible window/screen */
6581     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
6582 #else
6583     redraw_mask = REDRAW_ALL;
6584 #endif
6585   }
6586 }