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