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