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