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