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