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