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