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