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