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