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