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