rnd-20100624-3-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "init.h"
18 #include "game.h"
19 #include "events.h"
20 #include "cartoons.h"
21 #include "network.h"
22 #include "tape.h"
23 #include "screens.h"
24
25
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX    0
28
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES        0
31 #define TOOL_CTRL_ID_NO         1
32 #define TOOL_CTRL_ID_CONFIRM    2
33 #define TOOL_CTRL_ID_PLAYER_1   3
34 #define TOOL_CTRL_ID_PLAYER_2   4
35 #define TOOL_CTRL_ID_PLAYER_3   5
36 #define TOOL_CTRL_ID_PLAYER_4   6
37
38 #define NUM_TOOL_BUTTONS        7
39
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
45
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
48
49 static char *print_if_not_empty(int element)
50 {
51   static char *s = NULL;
52   char *token_name = element_info[element].token_name;
53
54   if (s != NULL)
55     free(s);
56
57   s = checked_malloc(strlen(token_name) + 10 + 1);
58
59   if (element != EL_EMPTY)
60     sprintf(s, "%d\t['%s']", element, token_name);
61   else
62     sprintf(s, "%d", element);
63
64   return s;
65 }
66
67 void DumpTile(int x, int y)
68 {
69   int sx = SCREENX(x);
70   int sy = SCREENY(y);
71
72   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
73   {
74     x--;
75     y--;
76   }
77
78   printf_line("-", 79);
79   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
80   printf_line("-", 79);
81
82   if (!IN_LEV_FIELD(x, y))
83   {
84     printf("(not in level field)\n");
85     printf("\n");
86
87     return;
88   }
89
90   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
91          element_info[Feld[x][y]].token_name);
92   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
93   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
94   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
95   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96   printf("  MovPos:      %d\n", MovPos[x][y]);
97   printf("  MovDir:      %d\n", MovDir[x][y]);
98   printf("  MovDelay:    %d\n", MovDelay[x][y]);
99   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
100   printf("  CustomValue: %d\n", CustomValue[x][y]);
101   printf("  GfxElement:  %d\n", GfxElement[x][y]);
102   printf("  GfxAction:   %d\n", GfxAction[x][y]);
103   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
104   printf("\n");
105 }
106
107 void SetDrawtoField(int mode)
108 {
109   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
110   {
111 #if NEW_TILESIZE
112 #if NEW_SCROLL
113     FX = 2 * TILEX_VAR;
114     FY = 2 * TILEY_VAR;
115     BX1 = -2;
116     BY1 = -2;
117     BX2 = SCR_FIELDX + 1;
118     BY2 = SCR_FIELDY + 1;
119     redraw_x1 = 2;
120     redraw_y1 = 2;
121 #else
122     FX = TILEX_VAR;
123     FY = TILEY_VAR;
124     BX1 = -1;
125     BY1 = -1;
126     BX2 = SCR_FIELDX;
127     BY2 = SCR_FIELDY;
128     redraw_x1 = 1;
129     redraw_y1 = 1;
130 #endif
131 #else
132 #if NEW_SCROLL
133     FX = 2 * TILEX;
134     FY = 2 * TILEY;
135     BX1 = -2;
136     BY1 = -2;
137     BX2 = SCR_FIELDX + 1;
138     BY2 = SCR_FIELDY + 1;
139     redraw_x1 = 2;
140     redraw_y1 = 2;
141 #else
142     FX = TILEX;
143     FY = TILEY;
144     BX1 = -1;
145     BY1 = -1;
146     BX2 = SCR_FIELDX;
147     BY2 = SCR_FIELDY;
148     redraw_x1 = 1;
149     redraw_y1 = 1;
150 #endif
151 #endif
152
153     drawto_field = fieldbuffer;
154   }
155   else  /* DRAW_BACKBUFFER */
156   {
157     FX = SX;
158     FY = SY;
159     BX1 = 0;
160     BY1 = 0;
161     BX2 = SCR_FIELDX - 1;
162     BY2 = SCR_FIELDY - 1;
163     redraw_x1 = 0;
164     redraw_y1 = 0;
165
166     drawto_field = backbuffer;
167   }
168 }
169
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
171 {
172   if (game_status == GAME_MODE_PLAYING &&
173       level.game_engine_type == GAME_ENGINE_TYPE_EM)
174   {
175     /* currently there is no partial redraw -- always redraw whole playfield */
176     RedrawPlayfield_EM(TRUE);
177
178     /* blit playfield from scroll buffer to normal back buffer for fading in */
179     BlitScreenToBitmap_EM(backbuffer);
180   }
181   else if (game_status == GAME_MODE_PLAYING &&
182            level.game_engine_type == GAME_ENGINE_TYPE_SP)
183   {
184     /* currently there is no partial redraw -- always redraw whole playfield */
185     RedrawPlayfield_SP(TRUE);
186
187     /* blit playfield from scroll buffer to normal back buffer for fading in */
188     BlitScreenToBitmap_SP(backbuffer);
189   }
190   else if (game_status == GAME_MODE_PLAYING &&
191            !game.envelope_active)
192   {
193     if (force_redraw)
194     {
195       x = gfx.sx - TILEX;
196       y = gfx.sy - TILEY;
197       width = gfx.sxsize + 2 * TILEX;
198       height = gfx.sysize + 2 * TILEY;
199     }
200
201     if (force_redraw)
202     {
203       int xx, yy;
204       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
206
207       for (xx = BX1; xx <= BX2; xx++)
208         for (yy = BY1; yy <= BY2; yy++)
209           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210             DrawScreenField(xx, yy);
211       DrawAllPlayers();
212     }
213
214     if (setup.soft_scrolling)
215     {
216       int fx = FX, fy = FY;
217
218       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
220
221       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
222     }
223   }
224
225   if (force_redraw)
226   {
227     x = gfx.sx;
228     y = gfx.sy;
229     width = gfx.sxsize;
230     height = gfx.sysize;
231   }
232
233   BlitBitmap(drawto, window, x, y, width, height, x, y);
234 }
235
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
237 {
238   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
239
240   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
242 }
243
244 void DrawMaskedBorder_FIELD()
245 {
246   if (global.border_status >= GAME_MODE_TITLE &&
247       global.border_status <= GAME_MODE_PLAYING &&
248       border.draw_masked[global.border_status])
249     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
250 }
251
252 void DrawMaskedBorder_DOOR_1()
253 {
254   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255       (global.border_status != GAME_MODE_EDITOR ||
256        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
258 }
259
260 void DrawMaskedBorder_DOOR_2()
261 {
262   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263       global.border_status != GAME_MODE_EDITOR)
264     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
265 }
266
267 void DrawMaskedBorder_DOOR_3()
268 {
269   /* currently not available */
270 }
271
272 void DrawMaskedBorder_ALL()
273 {
274   DrawMaskedBorder_FIELD();
275   DrawMaskedBorder_DOOR_1();
276   DrawMaskedBorder_DOOR_2();
277   DrawMaskedBorder_DOOR_3();
278 }
279
280 void DrawMaskedBorder(int redraw_mask)
281 {
282   /* never draw masked screen borders on borderless screens */
283   if (effectiveGameStatus() == GAME_MODE_LOADING ||
284       effectiveGameStatus() == GAME_MODE_TITLE)
285     return;
286
287   /* never draw masked screen borders when displaying request outside door */
288   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289       global.use_envelope_request)
290     return;
291
292   if (redraw_mask & REDRAW_ALL)
293     DrawMaskedBorder_ALL();
294   else
295   {
296     if (redraw_mask & REDRAW_FIELD)
297       DrawMaskedBorder_FIELD();
298     if (redraw_mask & REDRAW_DOOR_1)
299       DrawMaskedBorder_DOOR_1();
300     if (redraw_mask & REDRAW_DOOR_2)
301       DrawMaskedBorder_DOOR_2();
302     if (redraw_mask & REDRAW_DOOR_3)
303       DrawMaskedBorder_DOOR_3();
304   }
305 }
306
307 void BackToFront()
308 {
309   int x, y;
310   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
311
312 #if 0
313   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
314   for (x = 0; x < SCR_FIELDX; x++)
315     for (y = 0 ; y < SCR_FIELDY; y++)
316       if (redraw[redraw_x1 + x][redraw_y1 + y])
317         printf("::: - %d, %d [%s]\n",
318                LEVELX(x), LEVELY(y),
319                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
320 #endif
321
322   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
323     redraw_mask |= REDRAW_FIELD;
324
325   if (redraw_mask & REDRAW_FIELD)
326     redraw_mask &= ~REDRAW_TILES;
327
328   if (redraw_mask == REDRAW_NONE)
329     return;
330
331   if (redraw_mask & REDRAW_TILES &&
332       game_status == GAME_MODE_PLAYING &&
333       border.draw_masked[GAME_MODE_PLAYING])
334     redraw_mask |= REDRAW_FIELD;
335
336   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
337   {
338     static boolean last_frame_skipped = FALSE;
339     boolean skip_even_when_not_scrolling = TRUE;
340     boolean just_scrolling = (ScreenMovDir != 0);
341     boolean verbose = FALSE;
342
343     if (global.fps_slowdown_factor > 1 &&
344         (FrameCounter % global.fps_slowdown_factor) &&
345         (just_scrolling || skip_even_when_not_scrolling))
346     {
347       redraw_mask &= ~REDRAW_MAIN;
348
349       last_frame_skipped = TRUE;
350
351       if (verbose)
352         printf("FRAME SKIPPED\n");
353     }
354     else
355     {
356       if (last_frame_skipped)
357         redraw_mask |= REDRAW_FIELD;
358
359       last_frame_skipped = FALSE;
360
361       if (verbose)
362         printf("frame not skipped\n");
363     }
364   }
365
366   /* synchronize X11 graphics at this point; if we would synchronize the
367      display immediately after the buffer switching (after the XFlush),
368      this could mean that we have to wait for the graphics to complete,
369      although we could go on doing calculations for the next frame */
370
371   SyncDisplay();
372
373   /* never draw masked border to backbuffer when using playfield buffer */
374   if (game_status != GAME_MODE_PLAYING ||
375       redraw_mask & REDRAW_FROM_BACKBUFFER ||
376       buffer == backbuffer)
377     DrawMaskedBorder(redraw_mask);
378   else
379     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
380
381   if (redraw_mask & REDRAW_ALL)
382   {
383     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
384
385     redraw_mask = REDRAW_NONE;
386   }
387
388   if (redraw_mask & REDRAW_FIELD)
389   {
390 #if 0
391     printf("::: REDRAW_FIELD\n");
392 #endif
393
394     if (game_status != GAME_MODE_PLAYING ||
395         redraw_mask & REDRAW_FROM_BACKBUFFER)
396     {
397       BlitBitmap(backbuffer, window,
398                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
399     }
400     else
401     {
402       int fx = FX, fy = FY;
403
404       if (setup.soft_scrolling)
405       {
406 #if NEW_TILESIZE
407         int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
408         int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
409
410         fx += dx * TILESIZE_VAR / TILESIZE;
411         fy += dy * TILESIZE_VAR / TILESIZE;
412 #else
413         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
414         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
415 #endif
416
417 #if 0
418         printf("::: %d, %d [%d, %d] [%d, %d]\n",
419                fx, fy, FX, FY, ScreenMovDir, ScreenGfxPos);
420 #endif
421
422 #if 0
423 #if NEW_TILESIZE
424         fx = fx * TILESIZE_VAR / TILESIZE;
425         fy = fy * TILESIZE_VAR / TILESIZE;
426 #endif
427 #endif
428       }
429
430       if (setup.soft_scrolling ||
431           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
432           ABS(ScreenMovPos) == ScrollStepSize ||
433           redraw_tiles > REDRAWTILES_THRESHOLD)
434       {
435         if (border.draw_masked[GAME_MODE_PLAYING])
436         {
437           if (buffer != backbuffer)
438           {
439             /* copy playfield buffer to backbuffer to add masked border */
440             BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
441             DrawMaskedBorder(REDRAW_FIELD);
442           }
443
444           BlitBitmap(backbuffer, window,
445                      REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
446                      REAL_SX, REAL_SY);
447         }
448         else
449         {
450           BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
451         }
452
453 #if 0
454 #ifdef DEBUG
455         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
456                ScreenGfxPos,
457                (setup.soft_scrolling ?
458                 "setup.soft_scrolling" :
459                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
460                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
461                 ABS(ScreenGfxPos) == ScrollStepSize ?
462                 "ABS(ScreenGfxPos) == ScrollStepSize" :
463                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
464 #endif
465 #endif
466       }
467     }
468
469     redraw_mask &= ~REDRAW_MAIN;
470   }
471
472   if (redraw_mask & REDRAW_DOORS)
473   {
474     if (redraw_mask & REDRAW_DOOR_1)
475       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
476
477     if (redraw_mask & REDRAW_DOOR_2)
478       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
479
480     if (redraw_mask & REDRAW_DOOR_3)
481       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
482
483     redraw_mask &= ~REDRAW_DOORS;
484   }
485
486   if (redraw_mask & REDRAW_MICROLEVEL)
487   {
488     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
489                SX, SY + 10 * TILEY);
490
491     redraw_mask &= ~REDRAW_MICROLEVEL;
492   }
493
494   if (redraw_mask & REDRAW_TILES)
495   {
496 #if 0
497     printf("::: REDRAW_TILES\n");
498 #endif
499
500 #if NEW_TILESIZE
501     for (x = 0; x < SCR_FIELDX; x++)
502       for (y = 0 ; y < SCR_FIELDY; y++)
503         if (redraw[redraw_x1 + x][redraw_y1 + y])
504           BlitBitmap(buffer, window,
505                      FX + x * TILEX_VAR, FY + y * TILEY_VAR,
506                      TILEX_VAR, TILEY_VAR,
507                      SX + x * TILEX_VAR, SY + y * TILEY_VAR);
508 #else
509     for (x = 0; x < SCR_FIELDX; x++)
510       for (y = 0 ; y < SCR_FIELDY; y++)
511         if (redraw[redraw_x1 + x][redraw_y1 + y])
512           BlitBitmap(buffer, window,
513                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
514                      SX + x * TILEX, SY + y * TILEY);
515 #endif
516   }
517
518   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
519   {
520     char text[100];
521     char info1[100];
522
523     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
524     if (!global.fps_slowdown)
525       info1[0] = '\0';
526
527     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
528 #if 1
529     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
530 #else
531     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
532 #endif
533   }
534
535   FlushDisplay();
536
537   for (x = 0; x < MAX_BUF_XSIZE; x++)
538     for (y = 0; y < MAX_BUF_YSIZE; y++)
539       redraw[x][y] = 0;
540   redraw_tiles = 0;
541   redraw_mask = REDRAW_NONE;
542 }
543
544 static void FadeCrossSaveBackbuffer()
545 {
546   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
547 }
548
549 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
550 {
551   static int fade_type_skip = FADE_TYPE_NONE;
552   void (*draw_border_function)(void) = NULL;
553   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
554   int x, y, width, height;
555   int fade_delay, post_delay;
556
557   if (fade_type == FADE_TYPE_FADE_OUT)
558   {
559     if (fade_type_skip != FADE_TYPE_NONE)
560     {
561 #if 0
562       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
563 #endif
564
565       /* skip all fade operations until specified fade operation */
566       if (fade_type & fade_type_skip)
567         fade_type_skip = FADE_TYPE_NONE;
568
569       return;
570     }
571
572     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
573     {
574       FadeCrossSaveBackbuffer();
575
576       return;
577     }
578   }
579
580   redraw_mask |= fade_mask;
581
582   if (fade_type == FADE_TYPE_SKIP)
583   {
584 #if 0
585     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
586 #endif
587
588     fade_type_skip = fade_mode;
589
590     return;
591   }
592
593 #if 0
594   printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
595          fade_type_skip);
596 #endif
597
598 #if 1
599   fade_delay = fading.fade_delay;
600   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
601 #endif
602
603   if (fade_type_skip != FADE_TYPE_NONE)
604   {
605 #if 0
606     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
607 #endif
608
609     /* skip all fade operations until specified fade operation */
610     if (fade_type & fade_type_skip)
611       fade_type_skip = FADE_TYPE_NONE;
612
613 #if 1
614     fade_delay = 0;
615 #else
616     return;
617 #endif
618   }
619
620 #if 1
621   if (global.autoplay_leveldir)
622   {
623     // fading.fade_mode = FADE_MODE_NONE;
624
625     return;
626   }
627 #endif
628
629 #if 0
630   if (fading.fade_mode == FADE_MODE_NONE)
631   {
632     BackToFront();
633
634     return;
635   }
636 #endif
637
638   /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
639
640 #if 0
641   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
642 #endif
643
644 #if 0
645   if (fade_mask == REDRAW_NONE)
646     fade_mask = REDRAW_FIELD;
647 #endif
648
649   // if (fade_mask & REDRAW_FIELD)
650   if (fade_mask == REDRAW_FIELD)
651   {
652     x = REAL_SX;
653     y = REAL_SY;
654     width  = FULL_SXSIZE;
655     height = FULL_SYSIZE;
656
657 #if 0
658     fade_delay = fading.fade_delay;
659     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
660 #endif
661
662     if (border.draw_masked_when_fading)
663       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
664     else
665       DrawMaskedBorder_FIELD();                         /* draw once */
666   }
667   else          /* REDRAW_ALL */
668   {
669     x = 0;
670     y = 0;
671     width  = WIN_XSIZE;
672     height = WIN_YSIZE;
673
674 #if 0
675     fade_delay = fading.fade_delay;
676     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
677 #endif
678   }
679
680 #if 1
681   if (!setup.fade_screens ||
682       fade_delay == 0 ||
683       fading.fade_mode == FADE_MODE_NONE)
684 #else
685   if (!setup.fade_screens || fade_delay == 0)
686 #endif
687   {
688     if (fade_mode == FADE_MODE_FADE_OUT)
689       return;
690
691 #if 0
692     if (fade_mode == FADE_MODE_FADE_OUT &&
693         fading.fade_mode != FADE_MODE_NONE)
694       ClearRectangle(backbuffer, x, y, width, height);
695 #endif
696
697 #if 1
698     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
699     redraw_mask = REDRAW_NONE;
700 #else
701     BackToFront();
702 #endif
703
704     return;
705   }
706
707   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
708                 draw_border_function);
709
710   redraw_mask &= ~fade_mask;
711 }
712
713 void FadeIn(int fade_mask)
714 {
715   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
716     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
717   else
718     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
719 }
720
721 void FadeOut(int fade_mask)
722 {
723   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
724     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
725   else
726     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
727
728   global.border_status = game_status;
729 }
730
731 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
732 {
733   static struct TitleFadingInfo fading_leave_stored;
734
735   if (set)
736     fading_leave_stored = fading_leave;
737   else
738     fading = fading_leave_stored;
739 }
740
741 void FadeSetEnterMenu()
742 {
743   fading = menu.enter_menu;
744
745 #if 0
746   printf("::: storing enter_menu\n");
747 #endif
748
749   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
750 }
751
752 void FadeSetLeaveMenu()
753 {
754   fading = menu.leave_menu;
755
756 #if 0
757   printf("::: storing leave_menu\n");
758 #endif
759
760   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
761 }
762
763 void FadeSetEnterScreen()
764 {
765   fading = menu.enter_screen[game_status];
766
767 #if 0
768   printf("::: storing leave_screen[%d]\n", game_status);
769 #endif
770
771   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
772 }
773
774 void FadeSetNextScreen()
775 {
776   fading = menu.next_screen;
777
778 #if 0
779   printf("::: storing next_screen\n");
780 #endif
781
782   // (do not overwrite fade mode set by FadeSetEnterScreen)
783   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
784 }
785
786 void FadeSetLeaveScreen()
787 {
788 #if 0
789   printf("::: recalling last stored value\n");
790 #endif
791
792   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
793 }
794
795 void FadeSetFromType(int type)
796 {
797   if (type & TYPE_ENTER_SCREEN)
798     FadeSetEnterScreen();
799   else if (type & TYPE_ENTER)
800     FadeSetEnterMenu();
801   else if (type & TYPE_LEAVE)
802     FadeSetLeaveMenu();
803 }
804
805 void FadeSetDisabled()
806 {
807   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
808
809   fading = fading_none;
810 }
811
812 void FadeSkipNextFadeIn()
813 {
814   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
815 }
816
817 void FadeSkipNextFadeOut()
818 {
819   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
820 }
821
822 void SetWindowBackgroundImageIfDefined(int graphic)
823 {
824   if (graphic_info[graphic].bitmap)
825     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
826 }
827
828 void SetMainBackgroundImageIfDefined(int graphic)
829 {
830   if (graphic_info[graphic].bitmap)
831     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
832 }
833
834 void SetDoorBackgroundImageIfDefined(int graphic)
835 {
836   if (graphic_info[graphic].bitmap)
837     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
838 }
839
840 void SetWindowBackgroundImage(int graphic)
841 {
842   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
843                             graphic_info[graphic].bitmap ?
844                             graphic_info[graphic].bitmap :
845                             graphic_info[IMG_BACKGROUND].bitmap);
846 }
847
848 void SetMainBackgroundImage(int graphic)
849 {
850   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
851                           graphic_info[graphic].bitmap ?
852                           graphic_info[graphic].bitmap :
853                           graphic_info[IMG_BACKGROUND].bitmap);
854 }
855
856 void SetDoorBackgroundImage(int graphic)
857 {
858   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
859                           graphic_info[graphic].bitmap ?
860                           graphic_info[graphic].bitmap :
861                           graphic_info[IMG_BACKGROUND].bitmap);
862 }
863
864 void SetPanelBackground()
865 {
866 #if 1
867   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
868
869 #if 1
870   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
871                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
872 #else
873   /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
874   ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
875   BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
876              MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
877 #endif
878 #else
879   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
880              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
881 #endif
882
883   SetDoorBackgroundBitmap(bitmap_db_panel);
884 }
885
886 void DrawBackground(int x, int y, int width, int height)
887 {
888   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
889   /* (when entering hall of fame after playing) */
890 #if 0
891   ClearRectangleOnBackground(drawto, x, y, width, height);
892 #else
893   ClearRectangleOnBackground(backbuffer, x, y, width, height);
894 #endif
895
896   redraw_mask |= REDRAW_FIELD;
897 }
898
899 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
900 {
901   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
902
903   if (font->bitmap == NULL)
904     return;
905
906   DrawBackground(x, y, width, height);
907 }
908
909 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
910 {
911   struct GraphicInfo *g = &graphic_info[graphic];
912
913   if (g->bitmap == NULL)
914     return;
915
916   DrawBackground(x, y, width, height);
917 }
918
919 void ClearField()
920 {
921   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
922   /* (when entering hall of fame after playing) */
923   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
924
925   /* !!! maybe this should be done before clearing the background !!! */
926   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
927   {
928     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
929     SetDrawtoField(DRAW_BUFFERED);
930   }
931   else
932     SetDrawtoField(DRAW_BACKBUFFER);
933 }
934
935 void MarkTileDirty(int x, int y)
936 {
937   int xx = redraw_x1 + x;
938   int yy = redraw_y1 + y;
939
940   if (!redraw[xx][yy])
941     redraw_tiles++;
942
943   redraw[xx][yy] = TRUE;
944   redraw_mask |= REDRAW_TILES;
945 }
946
947 void SetBorderElement()
948 {
949   int x, y;
950
951   BorderElement = EL_EMPTY;
952
953   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
954   {
955     for (x = 0; x < lev_fieldx; x++)
956     {
957       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
958         BorderElement = EL_STEELWALL;
959
960       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
961         x = lev_fieldx - 2;
962     }
963   }
964 }
965
966 void FloodFillLevel(int from_x, int from_y, int fill_element,
967                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
968                     int max_fieldx, int max_fieldy)
969 {
970   int i,x,y;
971   int old_element;
972   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
973   static int safety = 0;
974
975   /* check if starting field still has the desired content */
976   if (field[from_x][from_y] == fill_element)
977     return;
978
979   safety++;
980
981   if (safety > max_fieldx * max_fieldy)
982     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
983
984   old_element = field[from_x][from_y];
985   field[from_x][from_y] = fill_element;
986
987   for (i = 0; i < 4; i++)
988   {
989     x = from_x + check[i][0];
990     y = from_y + check[i][1];
991
992     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
993       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
994   }
995
996   safety--;
997 }
998
999 void SetRandomAnimationValue(int x, int y)
1000 {
1001   gfx.anim_random_frame = GfxRandom[x][y];
1002 }
1003
1004 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1005 {
1006   /* animation synchronized with global frame counter, not move position */
1007   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1008     sync_frame = FrameCounter;
1009
1010   return getAnimationFrame(graphic_info[graphic].anim_frames,
1011                            graphic_info[graphic].anim_delay,
1012                            graphic_info[graphic].anim_mode,
1013                            graphic_info[graphic].anim_start_frame,
1014                            sync_frame);
1015 }
1016
1017 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1018                               Bitmap **bitmap, int *x, int *y,
1019                               boolean get_backside)
1020 {
1021   struct
1022   {
1023     int width_mult, width_div;
1024     int height_mult, height_div;
1025   }
1026   offset_calc[6] =
1027   {
1028     { 15, 16,   2, 3    },      /* 1 x 1 */
1029     { 7, 8,     2, 3    },      /* 2 x 2 */
1030     { 3, 4,     2, 3    },      /* 4 x 4 */
1031     { 1, 2,     2, 3    },      /* 8 x 8 */
1032     { 0, 1,     2, 3    },      /* 16 x 16 */
1033     { 0, 1,     0, 1    },      /* 32 x 32 */
1034   };
1035   struct GraphicInfo *g = &graphic_info[graphic];
1036   Bitmap *src_bitmap = g->bitmap;
1037   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1038   int offset_calc_pos = log_2(tilesize);
1039   int width_mult  = offset_calc[offset_calc_pos].width_mult;
1040   int width_div   = offset_calc[offset_calc_pos].width_div;
1041   int height_mult = offset_calc[offset_calc_pos].height_mult;
1042   int height_div  = offset_calc[offset_calc_pos].height_div;
1043   int startx = src_bitmap->width * width_mult / width_div;
1044   int starty = src_bitmap->height * height_mult / height_div;
1045 #if NEW_TILESIZE
1046   int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1047     tilesize / TILESIZE;
1048   int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1049     tilesize / TILESIZE;
1050 #else
1051   int src_x = g->src_x * tilesize / TILESIZE;
1052   int src_y = g->src_y * tilesize / TILESIZE;
1053 #endif
1054   int width = g->width * tilesize / TILESIZE;
1055   int height = g->height * tilesize / TILESIZE;
1056   int offset_x = g->offset_x * tilesize / TILESIZE;
1057   int offset_y = g->offset_y * tilesize / TILESIZE;
1058
1059   if (g->offset_y == 0)         /* frames are ordered horizontally */
1060   {
1061     int max_width = g->anim_frames_per_line * width;
1062     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1063
1064     src_x = pos % max_width;
1065     src_y = src_y % height + pos / max_width * height;
1066   }
1067   else if (g->offset_x == 0)    /* frames are ordered vertically */
1068   {
1069     int max_height = g->anim_frames_per_line * height;
1070     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1071
1072     src_x = src_x % width + pos / max_height * width;
1073     src_y = pos % max_height;
1074   }
1075   else                          /* frames are ordered diagonally */
1076   {
1077     src_x = src_x + frame * offset_x;
1078     src_y = src_y + frame * offset_y;
1079   }
1080
1081   *bitmap = src_bitmap;
1082   *x = startx + src_x;
1083   *y = starty + src_y;
1084 }
1085
1086 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1087                               int *x, int *y, boolean get_backside)
1088 {
1089   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1090                            get_backside);
1091 }
1092
1093 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1094                            Bitmap **bitmap, int *x, int *y)
1095 {
1096   getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1097 }
1098
1099 void getFixedGraphicSource(int graphic, int frame,
1100                            Bitmap **bitmap, int *x, int *y)
1101 {
1102   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1103 }
1104
1105 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1106 {
1107 #if 1
1108   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1109 #else
1110   struct GraphicInfo *g = &graphic_info[graphic];
1111   int mini_startx = 0;
1112   int mini_starty = g->bitmap->height * 2 / 3;
1113
1114   *bitmap = g->bitmap;
1115   *x = mini_startx + g->src_x / 2;
1116   *y = mini_starty + g->src_y / 2;
1117 #endif
1118 }
1119
1120 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1121                                 int *x, int *y, boolean get_backside)
1122 {
1123   struct GraphicInfo *g = &graphic_info[graphic];
1124   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1125   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1126
1127 #if NEW_TILESIZE
1128   if (TILESIZE_VAR != TILESIZE)
1129     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1130                                     get_backside);
1131 #endif
1132
1133   *bitmap = g->bitmap;
1134
1135   if (g->offset_y == 0)         /* frames are ordered horizontally */
1136   {
1137     int max_width = g->anim_frames_per_line * g->width;
1138     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1139
1140     *x = pos % max_width;
1141     *y = src_y % g->height + pos / max_width * g->height;
1142   }
1143   else if (g->offset_x == 0)    /* frames are ordered vertically */
1144   {
1145     int max_height = g->anim_frames_per_line * g->height;
1146     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1147
1148     *x = src_x % g->width + pos / max_height * g->width;
1149     *y = pos % max_height;
1150   }
1151   else                          /* frames are ordered diagonally */
1152   {
1153     *x = src_x + frame * g->offset_x;
1154     *y = src_y + frame * g->offset_y;
1155   }
1156 }
1157
1158 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1159 {
1160   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1161 }
1162
1163 void DrawGraphic(int x, int y, int graphic, int frame)
1164 {
1165 #if DEBUG
1166   if (!IN_SCR_FIELD(x, y))
1167   {
1168     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1169     printf("DrawGraphic(): This should never happen!\n");
1170     return;
1171   }
1172 #endif
1173
1174 #if NEW_TILESIZE
1175   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1176                  frame);
1177 #else
1178   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1179 #endif
1180   MarkTileDirty(x, y);
1181 }
1182
1183 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1184 {
1185 #if DEBUG
1186   if (!IN_SCR_FIELD(x, y))
1187   {
1188     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1189     printf("DrawGraphic(): This should never happen!\n");
1190     return;
1191   }
1192 #endif
1193
1194   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1195                       frame);
1196   MarkTileDirty(x, y);
1197 }
1198
1199 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1200                     int frame)
1201 {
1202   Bitmap *src_bitmap;
1203   int src_x, src_y;
1204
1205   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1206 #if NEW_TILESIZE
1207   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1208 #else
1209   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1210 #endif
1211 }
1212
1213 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1214                          int frame)
1215 {
1216   Bitmap *src_bitmap;
1217   int src_x, src_y;
1218
1219   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1220   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1221 }
1222
1223 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1224 {
1225 #if DEBUG
1226   if (!IN_SCR_FIELD(x, y))
1227   {
1228     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1229     printf("DrawGraphicThruMask(): This should never happen!\n");
1230     return;
1231   }
1232 #endif
1233
1234 #if NEW_TILESIZE
1235   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1236                          graphic, frame);
1237 #else
1238   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1239                          frame);
1240 #endif
1241   MarkTileDirty(x, y);
1242 }
1243
1244 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1245 {
1246 #if DEBUG
1247   if (!IN_SCR_FIELD(x, y))
1248   {
1249     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1250     printf("DrawGraphicThruMask(): This should never happen!\n");
1251     return;
1252   }
1253 #endif
1254
1255   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1256                               graphic, frame);
1257   MarkTileDirty(x, y);
1258 }
1259
1260 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1261                             int frame)
1262 {
1263   Bitmap *src_bitmap;
1264   int src_x, src_y;
1265
1266   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1267
1268   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1269                 dst_x - src_x, dst_y - src_y);
1270 #if NEW_TILESIZE
1271   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1272                    dst_x, dst_y);
1273 #else
1274   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1275 #endif
1276 }
1277
1278 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1279                                  int graphic, int frame)
1280 {
1281   Bitmap *src_bitmap;
1282   int src_x, src_y;
1283
1284   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1285
1286   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1287                 dst_x - src_x, dst_y - src_y);
1288   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1289 }
1290
1291 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1292 {
1293   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1294                       frame, tilesize);
1295   MarkTileDirty(x / tilesize, y / tilesize);
1296 }
1297
1298 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1299                          int tilesize)
1300 {
1301   Bitmap *src_bitmap;
1302   int src_x, src_y;
1303
1304   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1305   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1306 }
1307
1308 void DrawMiniGraphic(int x, int y, int graphic)
1309 {
1310   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1311   MarkTileDirty(x / 2, y / 2);
1312 }
1313
1314 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1315 {
1316   Bitmap *src_bitmap;
1317   int src_x, src_y;
1318
1319   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1320   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1321 }
1322
1323 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1324                                             int graphic, int frame,
1325                                             int cut_mode, int mask_mode)
1326 {
1327   Bitmap *src_bitmap;
1328   int src_x, src_y;
1329   int dst_x, dst_y;
1330   int width = TILEX, height = TILEY;
1331   int cx = 0, cy = 0;
1332
1333   if (dx || dy)                 /* shifted graphic */
1334   {
1335     if (x < BX1)                /* object enters playfield from the left */
1336     {
1337       x = BX1;
1338       width = dx;
1339       cx = TILEX - dx;
1340       dx = 0;
1341     }
1342     else if (x > BX2)           /* object enters playfield from the right */
1343     {
1344       x = BX2;
1345       width = -dx;
1346       dx = TILEX + dx;
1347     }
1348     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1349     {
1350       width += dx;
1351       cx = -dx;
1352       dx = 0;
1353     }
1354     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1355       width -= dx;
1356     else if (dx)                /* general horizontal movement */
1357       MarkTileDirty(x + SIGN(dx), y);
1358
1359     if (y < BY1)                /* object enters playfield from the top */
1360     {
1361       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1362         return;
1363
1364       y = BY1;
1365       height = dy;
1366       cy = TILEY - dy;
1367       dy = 0;
1368     }
1369     else if (y > BY2)           /* object enters playfield from the bottom */
1370     {
1371       y = BY2;
1372       height = -dy;
1373       dy = TILEY + dy;
1374     }
1375     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1376     {
1377       height += dy;
1378       cy = -dy;
1379       dy = 0;
1380     }
1381     else if (dy > 0 && cut_mode == CUT_ABOVE)
1382     {
1383       if (y == BY2)             /* object completely above bottom border */
1384         return;
1385
1386       height = dy;
1387       cy = TILEY - dy;
1388       dy = TILEY;
1389       MarkTileDirty(x, y + 1);
1390     }                           /* object leaves playfield to the bottom */
1391     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1392       height -= dy;
1393     else if (dy)                /* general vertical movement */
1394       MarkTileDirty(x, y + SIGN(dy));
1395   }
1396
1397 #if DEBUG
1398   if (!IN_SCR_FIELD(x, y))
1399   {
1400     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1401     printf("DrawGraphicShifted(): This should never happen!\n");
1402     return;
1403   }
1404 #endif
1405
1406 #if NEW_TILESIZE
1407   width = width * TILESIZE_VAR / TILESIZE;
1408   height = height * TILESIZE_VAR / TILESIZE;
1409   cx = cx * TILESIZE_VAR / TILESIZE;
1410   cy = cy * TILESIZE_VAR / TILESIZE;
1411   dx = dx * TILESIZE_VAR / TILESIZE;
1412   dy = dy * TILESIZE_VAR / TILESIZE;
1413 #endif
1414
1415   if (width > 0 && height > 0)
1416   {
1417     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1418
1419     src_x += cx;
1420     src_y += cy;
1421
1422 #if NEW_TILESIZE
1423     dst_x = FX + x * TILEX_VAR + dx;
1424     dst_y = FY + y * TILEY_VAR + dy;
1425 #else
1426     dst_x = FX + x * TILEX + dx;
1427     dst_y = FY + y * TILEY + dy;
1428 #endif
1429
1430     if (mask_mode == USE_MASKING)
1431     {
1432       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1433                     dst_x - src_x, dst_y - src_y);
1434       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1435                        dst_x, dst_y);
1436     }
1437     else
1438       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1439                  dst_x, dst_y);
1440
1441     MarkTileDirty(x, y);
1442   }
1443 }
1444
1445 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1446                                             int graphic, int frame,
1447                                             int cut_mode, int mask_mode)
1448 {
1449   Bitmap *src_bitmap;
1450   int src_x, src_y;
1451   int dst_x, dst_y;
1452 #if NEW_TILESIZE
1453   int width = TILEX_VAR, height = TILEY_VAR;
1454 #else
1455   int width = TILEX, height = TILEY;
1456 #endif
1457   int x1 = x;
1458   int y1 = y;
1459   int x2 = x + SIGN(dx);
1460   int y2 = y + SIGN(dy);
1461 #if 0
1462   /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1463   int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1464 #else
1465   /* movement with two-tile animations must be sync'ed with movement position,
1466      not with current GfxFrame (which can be higher when using slow movement) */
1467   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1468   int anim_frames = graphic_info[graphic].anim_frames;
1469 #if 1
1470   /* (we also need anim_delay here for movement animations with less frames) */
1471   int anim_delay = graphic_info[graphic].anim_delay;
1472   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1473 #else
1474   int sync_frame = anim_pos * anim_frames / TILESIZE;
1475 #endif
1476 #endif
1477   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1478   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1479
1480   /* re-calculate animation frame for two-tile movement animation */
1481   frame = getGraphicAnimationFrame(graphic, sync_frame);
1482
1483 #if 0
1484 #if 0
1485   printf("::: %d, %d, %d => %d [%d]\n",
1486          anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1487 #else
1488   printf("::: %d, %d => %d\n",
1489          anim_pos, anim_frames, sync_frame);
1490 #endif
1491 #endif
1492
1493 #if 0
1494   printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1495          GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1496 #endif
1497
1498   /* check if movement start graphic inside screen area and should be drawn */
1499   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1500   {
1501     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1502
1503 #if NEW_TILESIZE
1504     dst_x = FX + x1 * TILEX_VAR;
1505     dst_y = FY + y1 * TILEY_VAR;
1506 #else
1507     dst_x = FX + x1 * TILEX;
1508     dst_y = FY + y1 * TILEY;
1509 #endif
1510
1511     if (mask_mode == USE_MASKING)
1512     {
1513       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1514                     dst_x - src_x, dst_y - src_y);
1515       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1516                        dst_x, dst_y);
1517     }
1518     else
1519       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1520                  dst_x, dst_y);
1521
1522     MarkTileDirty(x1, y1);
1523   }
1524
1525   /* check if movement end graphic inside screen area and should be drawn */
1526   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1527   {
1528     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1529
1530 #if NEW_TILESIZE
1531     dst_x = FX + x2 * TILEX_VAR;
1532     dst_y = FY + y2 * TILEY_VAR;
1533 #else
1534     dst_x = FX + x2 * TILEX;
1535     dst_y = FY + y2 * TILEY;
1536 #endif
1537
1538     if (mask_mode == USE_MASKING)
1539     {
1540       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1541                     dst_x - src_x, dst_y - src_y);
1542       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1543                        dst_x, dst_y);
1544     }
1545     else
1546       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1547                  dst_x, dst_y);
1548
1549     MarkTileDirty(x2, y2);
1550   }
1551 }
1552
1553 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1554                                int graphic, int frame,
1555                                int cut_mode, int mask_mode)
1556 {
1557   if (graphic < 0)
1558   {
1559     DrawGraphic(x, y, graphic, frame);
1560
1561     return;
1562   }
1563
1564   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1565     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1566   else
1567     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1568 }
1569
1570 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1571                                 int frame, int cut_mode)
1572 {
1573   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1574 }
1575
1576 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1577                           int cut_mode, int mask_mode)
1578 {
1579   int lx = LEVELX(x), ly = LEVELY(y);
1580   int graphic;
1581   int frame;
1582
1583   if (IN_LEV_FIELD(lx, ly))
1584   {
1585     SetRandomAnimationValue(lx, ly);
1586
1587     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1588     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1589
1590     /* do not use double (EM style) movement graphic when not moving */
1591     if (graphic_info[graphic].double_movement && !dx && !dy)
1592     {
1593       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1594       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1595     }
1596   }
1597   else  /* border element */
1598   {
1599     graphic = el2img(element);
1600     frame = getGraphicAnimationFrame(graphic, -1);
1601   }
1602
1603   if (element == EL_EXPANDABLE_WALL)
1604   {
1605     boolean left_stopped = FALSE, right_stopped = FALSE;
1606
1607     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1608       left_stopped = TRUE;
1609     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1610       right_stopped = TRUE;
1611
1612     if (left_stopped && right_stopped)
1613       graphic = IMG_WALL;
1614     else if (left_stopped)
1615     {
1616       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1617       frame = graphic_info[graphic].anim_frames - 1;
1618     }
1619     else if (right_stopped)
1620     {
1621       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1622       frame = graphic_info[graphic].anim_frames - 1;
1623     }
1624   }
1625
1626   if (dx || dy)
1627     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1628   else if (mask_mode == USE_MASKING)
1629     DrawGraphicThruMask(x, y, graphic, frame);
1630   else
1631     DrawGraphic(x, y, graphic, frame);
1632 }
1633
1634 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1635                          int cut_mode, int mask_mode)
1636 {
1637   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1638     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1639                          cut_mode, mask_mode);
1640 }
1641
1642 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1643                               int cut_mode)
1644 {
1645   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1646 }
1647
1648 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1649                              int cut_mode)
1650 {
1651   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1652 }
1653
1654 void DrawLevelElementThruMask(int x, int y, int element)
1655 {
1656   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1657 }
1658
1659 void DrawLevelFieldThruMask(int x, int y)
1660 {
1661   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1662 }
1663
1664 /* !!! implementation of quicksand is totally broken !!! */
1665 #define IS_CRUMBLED_TILE(x, y, e)                                       \
1666         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
1667                              !IS_MOVING(x, y) ||                        \
1668                              (e) == EL_QUICKSAND_EMPTYING ||            \
1669                              (e) == EL_QUICKSAND_FAST_EMPTYING))
1670
1671 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1672                                                int graphic)
1673 {
1674   Bitmap *src_bitmap;
1675   int src_x, src_y;
1676   int width, height, cx, cy;
1677   int sx = SCREENX(x), sy = SCREENY(y);
1678   int crumbled_border_size = graphic_info[graphic].border_size;
1679   int i;
1680
1681   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1682
1683   for (i = 1; i < 4; i++)
1684   {
1685     int dxx = (i & 1 ? dx : 0);
1686     int dyy = (i & 2 ? dy : 0);
1687     int xx = x + dxx;
1688     int yy = y + dyy;
1689     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1690                    BorderElement);
1691
1692     /* check if neighbour field is of same crumble type */
1693     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1694                     graphic_info[graphic].class ==
1695                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1696
1697     /* return if check prevents inner corner */
1698     if (same == (dxx == dx && dyy == dy))
1699       return;
1700   }
1701
1702   /* if we reach this point, we have an inner corner */
1703
1704   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1705
1706 #if NEW_TILESIZE
1707   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1708   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1709   cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1710   cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1711
1712   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1713              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1714 #else
1715   width  = crumbled_border_size;
1716   height = crumbled_border_size;
1717   cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1718   cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1719
1720   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1721              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1722 #endif
1723 }
1724
1725 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1726                                           int dir)
1727 {
1728   Bitmap *src_bitmap;
1729   int src_x, src_y;
1730   int width, height, bx, by, cx, cy;
1731   int sx = SCREENX(x), sy = SCREENY(y);
1732   int crumbled_border_size = graphic_info[graphic].border_size;
1733   int i;
1734
1735   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1736
1737   /* draw simple, sloppy, non-corner-accurate crumbled border */
1738
1739 #if 1
1740   width  = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1741   height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1742   cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1743   cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1744 #else
1745   if (dir == 1 || dir == 2)             /* left or right crumbled border */
1746   {
1747     width = crumbled_border_size;
1748     height = TILEY;
1749     cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1750     cy = 0;
1751   }
1752   else                                  /* top or bottom crumbled border */
1753   {
1754     width = TILEX;
1755     height = crumbled_border_size;
1756     cx = 0;
1757     cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1758   }
1759 #endif
1760
1761 #if NEW_TILESIZE
1762   BlitBitmap(src_bitmap, drawto_field,
1763              src_x + cx * TILESIZE_VAR / TILESIZE,
1764              src_y + cy * TILESIZE_VAR / TILESIZE,
1765              width * TILESIZE_VAR / TILESIZE,
1766              height * TILESIZE_VAR / TILESIZE,
1767              FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1768              FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1769 #else
1770   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1771              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1772 #endif
1773
1774   /* (remaining middle border part must be at least as big as corner part) */
1775   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1776       crumbled_border_size >= TILESIZE / 3)
1777     return;
1778
1779   /* correct corners of crumbled border, if needed */
1780
1781 #if 1
1782   for (i = -1; i <= 1; i+=2)
1783   {
1784     int xx = x + (dir == 0 || dir == 3 ? i : 0);
1785     int yy = y + (dir == 1 || dir == 2 ? i : 0);
1786     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1787                    BorderElement);
1788
1789     /* check if neighbour field is of same crumble type */
1790     if (IS_CRUMBLED_TILE(xx, yy, element) &&
1791         graphic_info[graphic].class ==
1792         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1793     {
1794       /* no crumbled corner, but continued crumbled border */
1795
1796       int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
1797       int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
1798       int b1 = (i == 1 ? crumbled_border_size :
1799                 TILESIZE - 2 * crumbled_border_size);
1800
1801       width  = crumbled_border_size;
1802       height = crumbled_border_size;
1803
1804       if (dir == 1 || dir == 2)
1805       {
1806         cx = c1;
1807         cy = c2;
1808         bx = cx;
1809         by = b1;
1810       }
1811       else
1812       {
1813         cx = c2;
1814         cy = c1;
1815         bx = b1;
1816         by = cy;
1817       }
1818
1819 #if NEW_TILESIZE
1820       BlitBitmap(src_bitmap, drawto_field,
1821                  src_x + bx * TILESIZE_VAR / TILESIZE,
1822                  src_y + by * TILESIZE_VAR / TILESIZE,
1823                  width * TILESIZE_VAR / TILESIZE,
1824                  height * TILESIZE_VAR / TILESIZE,
1825                  FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1826                  FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1827 #else
1828       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1829                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1830 #endif
1831     }
1832   }
1833 #else
1834   if (dir == 1 || dir == 2)             /* left or right crumbled border */
1835   {
1836     for (i = -1; i <= 1; i+=2)
1837     {
1838       int xx = x;
1839       int yy = y + i;
1840       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1841                      BorderElement);
1842
1843       /* check if neighbour field is of same crumble type */
1844       if (IS_CRUMBLED_TILE(xx, yy, element) &&
1845           graphic_info[graphic].class ==
1846           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1847       {
1848         /* no crumbled corner, but continued crumbled border */
1849
1850         width  = crumbled_border_size;
1851         height = crumbled_border_size;
1852         cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1853         cy = (i == 1 ? TILEY - crumbled_border_size : 0);
1854         bx = cx;
1855         by = (i == 1 ? crumbled_border_size :
1856               TILEY - 2 * crumbled_border_size);
1857
1858         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1859                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1860       }
1861     }
1862   }
1863   else                          /* top or bottom crumbled border */
1864   {
1865     for (i = -1; i <= 1; i+=2)
1866     {
1867       int xx = x + i;
1868       int yy = y;
1869       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1870                      BorderElement);
1871
1872       /* check if neighbour field is of same crumble type */
1873       if (IS_CRUMBLED_TILE(xx, yy, element) &&
1874           graphic_info[graphic].class ==
1875           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1876       {
1877         /* no crumbled corner, but continued crumbled border */
1878
1879         width  = crumbled_border_size;
1880         height = crumbled_border_size;
1881         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1882         cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1883         bx = (i == 1 ? crumbled_border_size :
1884               TILEX - 2 * crumbled_border_size);
1885         by = cy;
1886
1887         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1888                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1889       }
1890     }
1891   }
1892 #endif
1893 }
1894
1895 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1896 {
1897   int sx = SCREENX(x), sy = SCREENY(y);
1898   int element;
1899   int i;
1900   static int xy[4][2] =
1901   {
1902     { 0, -1 },
1903     { -1, 0 },
1904     { +1, 0 },
1905     { 0, +1 }
1906   };
1907
1908   if (!IN_LEV_FIELD(x, y))
1909     return;
1910
1911   element = TILE_GFX_ELEMENT(x, y);
1912
1913   /* crumble field itself */
1914   if (IS_CRUMBLED_TILE(x, y, element))
1915   {
1916     if (!IN_SCR_FIELD(sx, sy))
1917       return;
1918
1919     for (i = 0; i < 4; i++)
1920     {
1921       int xx = x + xy[i][0];
1922       int yy = y + xy[i][1];
1923
1924       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1925                  BorderElement);
1926
1927       /* check if neighbour field is of same crumble type */
1928 #if 1
1929       if (IS_CRUMBLED_TILE(xx, yy, element) &&
1930           graphic_info[graphic].class ==
1931           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1932         continue;
1933 #else
1934       if (IS_CRUMBLED_TILE(xx, yy, element))
1935         continue;
1936 #endif
1937
1938       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1939     }
1940
1941     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1942         graphic_info[graphic].anim_frames == 2)
1943     {
1944       for (i = 0; i < 4; i++)
1945       {
1946         int dx = (i & 1 ? +1 : -1);
1947         int dy = (i & 2 ? +1 : -1);
1948
1949         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1950       }
1951     }
1952
1953     MarkTileDirty(sx, sy);
1954   }
1955   else          /* center field not crumbled -- crumble neighbour fields */
1956   {
1957     for (i = 0; i < 4; i++)
1958     {
1959       int xx = x + xy[i][0];
1960       int yy = y + xy[i][1];
1961       int sxx = sx + xy[i][0];
1962       int syy = sy + xy[i][1];
1963
1964       if (!IN_LEV_FIELD(xx, yy) ||
1965           !IN_SCR_FIELD(sxx, syy))
1966         continue;
1967
1968       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1969         continue;
1970
1971       element = TILE_GFX_ELEMENT(xx, yy);
1972
1973       if (!IS_CRUMBLED_TILE(xx, yy, element))
1974         continue;
1975
1976       graphic = el_act2crm(element, ACTION_DEFAULT);
1977
1978       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1979
1980       MarkTileDirty(sxx, syy);
1981     }
1982   }
1983 }
1984
1985 void DrawLevelFieldCrumbled(int x, int y)
1986 {
1987   int graphic;
1988
1989   if (!IN_LEV_FIELD(x, y))
1990     return;
1991
1992 #if 1
1993   /* !!! CHECK THIS !!! */
1994
1995   /*
1996   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1997       GFX_CRUMBLED(GfxElement[x][y]))
1998   */
1999
2000   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2001       GfxElement[x][y] != EL_UNDEFINED &&
2002       GFX_CRUMBLED(GfxElement[x][y]))
2003   {
2004     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2005
2006     return;
2007   }
2008 #endif
2009
2010 #if 1
2011   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2012 #else
2013   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2014 #endif
2015
2016   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2017 }
2018
2019 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2020                                    int step_frame)
2021 {
2022   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2023   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2024   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2025   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2026   int sx = SCREENX(x), sy = SCREENY(y);
2027
2028   DrawGraphic(sx, sy, graphic1, frame1);
2029   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2030 }
2031
2032 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2033 {
2034   int sx = SCREENX(x), sy = SCREENY(y);
2035   static int xy[4][2] =
2036   {
2037     { 0, -1 },
2038     { -1, 0 },
2039     { +1, 0 },
2040     { 0, +1 }
2041   };
2042   int i;
2043
2044   for (i = 0; i < 4; i++)
2045   {
2046     int xx = x + xy[i][0];
2047     int yy = y + xy[i][1];
2048     int sxx = sx + xy[i][0];
2049     int syy = sy + xy[i][1];
2050
2051     if (!IN_LEV_FIELD(xx, yy) ||
2052         !IN_SCR_FIELD(sxx, syy) ||
2053         !GFX_CRUMBLED(Feld[xx][yy]) ||
2054         IS_MOVING(xx, yy))
2055       continue;
2056
2057     DrawLevelField(xx, yy);
2058   }
2059 }
2060
2061 static int getBorderElement(int x, int y)
2062 {
2063   int border[7][2] =
2064   {
2065     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
2066     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
2067     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2068     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2069     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
2070     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
2071     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
2072   };
2073   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2074   int steel_position = (x == -1         && y == -1              ? 0 :
2075                         x == lev_fieldx && y == -1              ? 1 :
2076                         x == -1         && y == lev_fieldy      ? 2 :
2077                         x == lev_fieldx && y == lev_fieldy      ? 3 :
2078                         x == -1         || x == lev_fieldx      ? 4 :
2079                         y == -1         || y == lev_fieldy      ? 5 : 6);
2080
2081   return border[steel_position][steel_type];
2082 }
2083
2084 void DrawScreenElement(int x, int y, int element)
2085 {
2086   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2087   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2088 }
2089
2090 void DrawLevelElement(int x, int y, int element)
2091 {
2092   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2093     DrawScreenElement(SCREENX(x), SCREENY(y), element);
2094 }
2095
2096 void DrawScreenField(int x, int y)
2097 {
2098   int lx = LEVELX(x), ly = LEVELY(y);
2099   int element, content;
2100
2101   if (!IN_LEV_FIELD(lx, ly))
2102   {
2103     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2104       element = EL_EMPTY;
2105     else
2106       element = getBorderElement(lx, ly);
2107
2108     DrawScreenElement(x, y, element);
2109
2110     return;
2111   }
2112
2113   element = Feld[lx][ly];
2114   content = Store[lx][ly];
2115
2116   if (IS_MOVING(lx, ly))
2117   {
2118     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2119     boolean cut_mode = NO_CUTTING;
2120
2121     if (element == EL_QUICKSAND_EMPTYING ||
2122         element == EL_QUICKSAND_FAST_EMPTYING ||
2123         element == EL_MAGIC_WALL_EMPTYING ||
2124         element == EL_BD_MAGIC_WALL_EMPTYING ||
2125         element == EL_DC_MAGIC_WALL_EMPTYING ||
2126         element == EL_AMOEBA_DROPPING)
2127       cut_mode = CUT_ABOVE;
2128     else if (element == EL_QUICKSAND_FILLING ||
2129              element == EL_QUICKSAND_FAST_FILLING ||
2130              element == EL_MAGIC_WALL_FILLING ||
2131              element == EL_BD_MAGIC_WALL_FILLING ||
2132              element == EL_DC_MAGIC_WALL_FILLING)
2133       cut_mode = CUT_BELOW;
2134
2135 #if 0
2136     if (lx == 9 && ly == 1)
2137       printf("::: %s [%d] [%d, %d] [%d]\n",
2138              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2139              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2140              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2141              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2142              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2143 #endif
2144
2145     if (cut_mode == CUT_ABOVE)
2146 #if 1
2147       DrawScreenElement(x, y, element);
2148 #else
2149       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2150 #endif
2151     else
2152       DrawScreenElement(x, y, EL_EMPTY);
2153
2154     if (horiz_move)
2155       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2156     else if (cut_mode == NO_CUTTING)
2157       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2158     else
2159     {
2160       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2161
2162 #if 1
2163       if (cut_mode == CUT_BELOW &&
2164           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2165         DrawLevelElement(lx, ly + 1, element);
2166 #endif
2167     }
2168
2169     if (content == EL_ACID)
2170     {
2171       int dir = MovDir[lx][ly];
2172       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2173       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2174
2175       DrawLevelElementThruMask(newlx, newly, EL_ACID);
2176     }
2177   }
2178   else if (IS_BLOCKED(lx, ly))
2179   {
2180     int oldx, oldy;
2181     int sx, sy;
2182     int horiz_move;
2183     boolean cut_mode = NO_CUTTING;
2184     int element_old, content_old;
2185
2186     Blocked2Moving(lx, ly, &oldx, &oldy);
2187     sx = SCREENX(oldx);
2188     sy = SCREENY(oldy);
2189     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2190                   MovDir[oldx][oldy] == MV_RIGHT);
2191
2192     element_old = Feld[oldx][oldy];
2193     content_old = Store[oldx][oldy];
2194
2195     if (element_old == EL_QUICKSAND_EMPTYING ||
2196         element_old == EL_QUICKSAND_FAST_EMPTYING ||
2197         element_old == EL_MAGIC_WALL_EMPTYING ||
2198         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2199         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2200         element_old == EL_AMOEBA_DROPPING)
2201       cut_mode = CUT_ABOVE;
2202
2203     DrawScreenElement(x, y, EL_EMPTY);
2204
2205     if (horiz_move)
2206       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2207                                NO_CUTTING);
2208     else if (cut_mode == NO_CUTTING)
2209       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2210                                cut_mode);
2211     else
2212       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2213                                cut_mode);
2214   }
2215   else if (IS_DRAWABLE(element))
2216     DrawScreenElement(x, y, element);
2217   else
2218     DrawScreenElement(x, y, EL_EMPTY);
2219 }
2220
2221 void DrawLevelField(int x, int y)
2222 {
2223   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2224     DrawScreenField(SCREENX(x), SCREENY(y));
2225   else if (IS_MOVING(x, y))
2226   {
2227     int newx,newy;
2228
2229     Moving2Blocked(x, y, &newx, &newy);
2230     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2231       DrawScreenField(SCREENX(newx), SCREENY(newy));
2232   }
2233   else if (IS_BLOCKED(x, y))
2234   {
2235     int oldx, oldy;
2236
2237     Blocked2Moving(x, y, &oldx, &oldy);
2238     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2239       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2240   }
2241 }
2242
2243 void DrawMiniElement(int x, int y, int element)
2244 {
2245   int graphic;
2246
2247   graphic = el2edimg(element);
2248   DrawMiniGraphic(x, y, graphic);
2249 }
2250
2251 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2252 {
2253   int x = sx + scroll_x, y = sy + scroll_y;
2254
2255   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2256     DrawMiniElement(sx, sy, EL_EMPTY);
2257   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2258     DrawMiniElement(sx, sy, Feld[x][y]);
2259   else
2260     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2261 }
2262
2263 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
2264                             int x, int y, int xsize, int ysize, int font_nr)
2265 {
2266   int font_width  = getFontWidth(font_nr);
2267   int font_height = getFontHeight(font_nr);
2268   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2269   Bitmap *src_bitmap;
2270   int src_x, src_y;
2271   int dst_x = SX + startx + x * font_width;
2272   int dst_y = SY + starty + y * font_height;
2273   int width  = graphic_info[graphic].width;
2274   int height = graphic_info[graphic].height;
2275   int inner_width  = MAX(width  - 2 * font_width,  font_width);
2276   int inner_height = MAX(height - 2 * font_height, font_height);
2277   int inner_sx = (width >= 3 * font_width ? font_width : 0);
2278   int inner_sy = (height >= 3 * font_height ? font_height : 0);
2279   boolean draw_masked = graphic_info[graphic].draw_masked;
2280
2281   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2282
2283   if (src_bitmap == NULL || width < font_width || height < font_height)
2284   {
2285     ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
2286     return;
2287   }
2288
2289   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
2290             inner_sx + (x - 1) * font_width  % inner_width);
2291   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
2292             inner_sy + (y - 1) * font_height % inner_height);
2293
2294   if (draw_masked)
2295   {
2296     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2297                   dst_x - src_x, dst_y - src_y);
2298     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2299                      dst_x, dst_y);
2300   }
2301   else
2302     BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
2303                dst_x, dst_y);
2304 }
2305
2306 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2307 {
2308   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2309   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2310   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2311   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2312   boolean no_delay = (tape.warp_forward);
2313   unsigned long anim_delay = 0;
2314   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2315   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2316   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2317   int font_width = getFontWidth(font_nr);
2318   int font_height = getFontHeight(font_nr);
2319   int max_xsize = level.envelope[envelope_nr].xsize;
2320   int max_ysize = level.envelope[envelope_nr].ysize;
2321   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2322   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2323   int xend = max_xsize;
2324   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2325   int xstep = (xstart < xend ? 1 : 0);
2326   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2327   int x, y;
2328
2329   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2330   {
2331     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2332     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2333     int sx = (SXSIZE - xsize * font_width)  / 2;
2334     int sy = (SYSIZE - ysize * font_height) / 2;
2335     int xx, yy;
2336
2337     SetDrawtoField(DRAW_BUFFERED);
2338
2339     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2340
2341     SetDrawtoField(DRAW_BACKBUFFER);
2342
2343     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2344       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2345
2346 #if 1
2347     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2348                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2349                    xsize - 2, ysize - 2, 0, mask_mode,
2350                    level.envelope[envelope_nr].autowrap,
2351                    level.envelope[envelope_nr].centered, FALSE);
2352 #else
2353     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2354                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2355                        xsize - 2, ysize - 2, mask_mode);
2356 #endif
2357
2358     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2359     BackToFront();
2360
2361     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2362   }
2363 }
2364
2365 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2366 {
2367 #if 1
2368   int envelope_nr = 0;
2369 #endif
2370   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2371   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2372   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2373   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2374   boolean no_delay = (tape.warp_forward);
2375   unsigned long anim_delay = 0;
2376   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2377   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2378 #if 1
2379   int max_word_len = maxWordLengthInString(text);
2380   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2381 #else
2382   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2383 #endif
2384   int font_width = getFontWidth(font_nr);
2385   int font_height = getFontHeight(font_nr);
2386 #if 1
2387
2388 #if 1
2389   int max_xsize = DXSIZE / font_width;
2390   int max_ysize = DYSIZE / font_height;
2391 #else
2392   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2393   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
2394 #endif
2395
2396 #else
2397   int max_xsize = level.envelope[envelope_nr].xsize;
2398   int max_ysize = level.envelope[envelope_nr].ysize;
2399 #endif
2400   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2401   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2402   int xend = max_xsize;
2403   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2404   int xstep = (xstart < xend ? 1 : 0);
2405   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2406   int x, y;
2407
2408 #if 1
2409   char *text_ptr;
2410   char *text_copy = getStringCopy(text);
2411 #else
2412 #if 1
2413   font_nr = FONT_TEXT_2;
2414
2415   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2416   {
2417     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2418     font_nr = FONT_TEXT_1;
2419   }
2420 #else
2421   int max_word_len = 0;
2422   char *text_ptr;
2423   char *text_copy = getStringCopy(text);
2424
2425   font_nr = FONT_TEXT_2;
2426
2427   for (text_ptr = text; *text_ptr; text_ptr++)
2428   {
2429     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2430
2431     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2432     {
2433       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2434       font_nr = FONT_TEXT_1;
2435
2436       break;
2437     }
2438   }
2439 #endif
2440 #endif
2441
2442 #if 1
2443   for (text_ptr = text_copy; *text_ptr; text_ptr++)
2444     if (*text_ptr == ' ')
2445       *text_ptr = '\n';
2446 #endif
2447
2448 #if 1
2449   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2450   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2451 #else
2452   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
2453   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2454 #endif
2455
2456   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2457   {
2458     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2459     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2460     int sx = (SXSIZE - xsize * font_width)  / 2;
2461     int sy = (SYSIZE - ysize * font_height) / 2;
2462     int xx, yy;
2463
2464 #if 1
2465     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2466 #else
2467     SetDrawtoField(DRAW_BUFFERED);
2468
2469     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2470
2471     SetDrawtoField(DRAW_BACKBUFFER);
2472 #endif
2473
2474     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2475       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2476
2477 #if 1
2478
2479 #if 1
2480     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2481                    text_copy, font_nr, max_xsize,
2482                    xsize - 2, ysize - 2, 2, mask_mode,
2483                    FALSE, TRUE, FALSE);
2484 #else
2485     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2486                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2487                    xsize - 2, ysize - 2, 0, mask_mode,
2488                    level.envelope[envelope_nr].autowrap,
2489                    level.envelope[envelope_nr].centered, FALSE);
2490 #endif
2491
2492 #else
2493     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2494                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2495                        xsize - 2, ysize - 2, mask_mode);
2496 #endif
2497
2498     /* copy request gadgets to door backbuffer */
2499 #if 1
2500     if ((ysize - 2) > 13)
2501       BlitBitmap(bitmap_db_door, drawto,
2502                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2503                  DOOR_GFX_PAGEY1 + 13 * font_height,
2504                  (xsize - 2) * font_width,
2505                  (ysize - 2 - 13) * font_height,
2506                  SX + sx + font_width,
2507                  SY + sy + font_height * (1 + 13));
2508 #else
2509     if ((ysize - 2) > 13)
2510       BlitBitmap(bitmap_db_door, drawto,
2511                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2512                  DOOR_GFX_PAGEY1 + 13 * font_height,
2513                  (xsize - 2) * font_width,
2514                  (ysize - 2 - 13) * font_height,
2515                  SX + sx + font_width,
2516                  SY + sy + font_height * (1 + 13));
2517 #endif
2518
2519 #if 1
2520     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2521     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2522 #else
2523     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2524 #endif
2525
2526 #if 1
2527     DoAnimation();
2528     BackToFront();
2529 #else
2530     BackToFront();
2531 #endif
2532
2533     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2534   }
2535
2536 #if 1
2537   free(text_copy);
2538 #endif
2539 }
2540
2541 void ShowEnvelope(int envelope_nr)
2542 {
2543   int element = EL_ENVELOPE_1 + envelope_nr;
2544   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2545   int sound_opening = element_info[element].sound[ACTION_OPENING];
2546   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2547   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2548   boolean no_delay = (tape.warp_forward);
2549   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2550   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2551   int anim_mode = graphic_info[graphic].anim_mode;
2552   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2553                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2554
2555   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2556
2557   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2558
2559   if (anim_mode == ANIM_DEFAULT)
2560     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2561
2562   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2563
2564   if (tape.playing)
2565     Delay(wait_delay_value);
2566   else
2567     WaitForEventToContinue();
2568
2569   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2570
2571   if (anim_mode != ANIM_NONE)
2572     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2573
2574   if (anim_mode == ANIM_DEFAULT)
2575     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2576
2577   game.envelope_active = FALSE;
2578
2579   SetDrawtoField(DRAW_BUFFERED);
2580
2581   redraw_mask |= REDRAW_FIELD;
2582   BackToFront();
2583 }
2584
2585 void ShowEnvelopeDoor(char *text, int action)
2586 {
2587 #if 1
2588   int last_game_status = game_status;   /* save current game status */
2589   // int last_draw_background_mask = gfx.draw_background_mask;
2590   int envelope_nr = 0;
2591 #endif
2592   int element = EL_ENVELOPE_1 + envelope_nr;
2593   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2594   int sound_opening = element_info[element].sound[ACTION_OPENING];
2595   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2596 #if 0
2597   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2598   boolean no_delay = (tape.warp_forward);
2599   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2600   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2601 #endif
2602   int anim_mode = graphic_info[graphic].anim_mode;
2603   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2604                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2605
2606 #if 1
2607   if (game_status == GAME_MODE_PLAYING)
2608   {
2609     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2610       BlitScreenToBitmap_EM(backbuffer);
2611     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2612       BlitScreenToBitmap_SP(backbuffer);
2613     else
2614     {
2615       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2616     }
2617   }
2618
2619   SetDrawtoField(DRAW_BACKBUFFER);
2620
2621   // SetDrawBackgroundMask(REDRAW_NONE);
2622
2623   if (action == ACTION_OPENING)
2624   {
2625     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2626
2627     if (game_status != GAME_MODE_MAIN)
2628       InitAnimation();
2629   }
2630
2631   /* force DOOR font inside door area */
2632   game_status = GAME_MODE_PSEUDO_DOOR;
2633 #endif
2634
2635   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2636
2637   if (action == ACTION_OPENING)
2638   {
2639     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2640
2641     if (anim_mode == ANIM_DEFAULT)
2642       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2643
2644     AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2645
2646 #if 0
2647     if (tape.playing)
2648       Delay(wait_delay_value);
2649     else
2650       WaitForEventToContinue();
2651 #endif
2652   }
2653   else
2654   {
2655     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2656
2657     if (anim_mode != ANIM_NONE)
2658       AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2659
2660     if (anim_mode == ANIM_DEFAULT)
2661       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2662   }
2663
2664   game.envelope_active = FALSE;
2665
2666 #if 1
2667   // game_status = last_game_status;    /* restore current game status */
2668
2669   if (action == ACTION_CLOSING)
2670   {
2671     if (game_status != GAME_MODE_MAIN)
2672       StopAnimation();
2673
2674     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2675   }
2676 #else
2677   SetDrawtoField(DRAW_BUFFERED);
2678 #endif
2679
2680   // SetDrawBackgroundMask(last_draw_background_mask);
2681
2682 #if 1
2683   redraw_mask = REDRAW_FIELD;
2684   // redraw_mask |= REDRAW_ALL;
2685 #else
2686   redraw_mask |= REDRAW_FIELD;
2687 #endif
2688
2689 #if 1
2690   if (game_status == GAME_MODE_MAIN)
2691     DoAnimation();
2692
2693   BackToFront();
2694
2695   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2696   game_status = last_game_status;       /* restore current game status */
2697
2698   if (game_status == GAME_MODE_PLAYING &&
2699       level.game_engine_type == GAME_ENGINE_TYPE_RND)
2700     SetDrawtoField(DRAW_BUFFERED);
2701 #else
2702   BackToFront();
2703 #endif
2704 }
2705
2706 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2707 {
2708   Bitmap *src_bitmap;
2709   int src_x, src_y;
2710   int graphic = el2preimg(element);
2711
2712   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2713   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2714 }
2715
2716 void DrawLevel()
2717 {
2718   int x,y;
2719
2720 #if 1
2721   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2722   SetDrawBackgroundMask(REDRAW_FIELD);
2723 #else
2724   SetDrawBackgroundMask(REDRAW_NONE);
2725 #endif
2726
2727   ClearField();
2728
2729   for (x = BX1; x <= BX2; x++)
2730     for (y = BY1; y <= BY2; y++)
2731       DrawScreenField(x, y);
2732
2733   redraw_mask |= REDRAW_FIELD;
2734 }
2735
2736 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2737 {
2738   int x,y;
2739
2740   for (x = 0; x < size_x; x++)
2741     for (y = 0; y < size_y; y++)
2742       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2743
2744   redraw_mask |= REDRAW_FIELD;
2745 }
2746
2747 static void DrawPreviewLevelExt(int from_x, int from_y)
2748 {
2749   boolean show_level_border = (BorderElement != EL_EMPTY);
2750   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2751   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2752   int tile_size = preview.tile_size;
2753   int preview_width  = preview.xsize * tile_size;
2754   int preview_height = preview.ysize * tile_size;
2755   int real_preview_xsize = MIN(level_xsize, preview.xsize);
2756   int real_preview_ysize = MIN(level_ysize, preview.ysize);
2757   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2758   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2759   int x, y;
2760
2761   DrawBackground(dst_x, dst_y, preview_width, preview_height);
2762
2763   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
2764   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2765
2766   for (x = 0; x < real_preview_xsize; x++)
2767   {
2768     for (y = 0; y < real_preview_ysize; y++)
2769     {
2770       int lx = from_x + x + (show_level_border ? -1 : 0);
2771       int ly = from_y + y + (show_level_border ? -1 : 0);
2772       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2773                      getBorderElement(lx, ly));
2774
2775       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2776                          element, tile_size);
2777     }
2778   }
2779
2780   redraw_mask |= REDRAW_MICROLEVEL;
2781 }
2782
2783 #define MICROLABEL_EMPTY                0
2784 #define MICROLABEL_LEVEL_NAME           1
2785 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
2786 #define MICROLABEL_LEVEL_AUTHOR         3
2787 #define MICROLABEL_IMPORTED_FROM_HEAD   4
2788 #define MICROLABEL_IMPORTED_FROM        5
2789 #define MICROLABEL_IMPORTED_BY_HEAD     6
2790 #define MICROLABEL_IMPORTED_BY          7
2791
2792 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2793 {
2794   int max_text_width = SXSIZE;
2795   int font_width = getFontWidth(font_nr);
2796
2797   if (pos->align == ALIGN_CENTER)
2798     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2799   else if (pos->align == ALIGN_RIGHT)
2800     max_text_width = pos->x;
2801   else
2802     max_text_width = SXSIZE - pos->x;
2803
2804   return max_text_width / font_width;
2805 }
2806
2807 static void DrawPreviewLevelLabelExt(int mode)
2808 {
2809   struct TextPosInfo *pos = &menu.main.text.level_info_2;
2810   char label_text[MAX_OUTPUT_LINESIZE + 1];
2811   int max_len_label_text;
2812 #if 1
2813   int font_nr = pos->font;
2814   int i;
2815
2816   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2817       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2818       mode == MICROLABEL_IMPORTED_BY_HEAD)
2819     font_nr = pos->font_alt;
2820 #else
2821   int font_nr = FONT_TEXT_2;
2822   int i;
2823
2824   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2825       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2826       mode == MICROLABEL_IMPORTED_BY_HEAD)
2827     font_nr = FONT_TEXT_3;
2828 #endif
2829
2830 #if 1
2831   max_len_label_text = getMaxTextLength(pos, font_nr);
2832 #else
2833   max_len_label_text = SXSIZE / getFontWidth(font_nr);
2834 #endif
2835
2836 #if 1
2837   if (pos->size != -1)
2838     max_len_label_text = pos->size;
2839 #endif
2840
2841   for (i = 0; i < max_len_label_text; i++)
2842     label_text[i] = ' ';
2843   label_text[max_len_label_text] = '\0';
2844
2845   if (strlen(label_text) > 0)
2846   {
2847 #if 1
2848     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2849 #else
2850     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2851     int lypos = MICROLABEL2_YPOS;
2852
2853     DrawText(lxpos, lypos, label_text, font_nr);
2854 #endif
2855   }
2856
2857   strncpy(label_text,
2858           (mode == MICROLABEL_LEVEL_NAME ? level.name :
2859            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2860            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2861            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2862            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2863            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2864            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2865           max_len_label_text);
2866   label_text[max_len_label_text] = '\0';
2867
2868   if (strlen(label_text) > 0)
2869   {
2870 #if 1
2871     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2872 #else
2873     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2874     int lypos = MICROLABEL2_YPOS;
2875
2876     DrawText(lxpos, lypos, label_text, font_nr);
2877 #endif
2878   }
2879
2880   redraw_mask |= REDRAW_MICROLEVEL;
2881 }
2882
2883 void DrawPreviewLevel(boolean restart)
2884 {
2885   static unsigned long scroll_delay = 0;
2886   static unsigned long label_delay = 0;
2887   static int from_x, from_y, scroll_direction;
2888   static int label_state, label_counter;
2889   unsigned long scroll_delay_value = preview.step_delay;
2890   boolean show_level_border = (BorderElement != EL_EMPTY);
2891   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2892   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2893   int last_game_status = game_status;           /* save current game status */
2894
2895 #if 0
2896   /* force PREVIEW font on preview level */
2897   game_status = GAME_MODE_PSEUDO_PREVIEW;
2898 #endif
2899
2900   if (restart)
2901   {
2902     from_x = 0;
2903     from_y = 0;
2904
2905     if (preview.anim_mode == ANIM_CENTERED)
2906     {
2907       if (level_xsize > preview.xsize)
2908         from_x = (level_xsize - preview.xsize) / 2;
2909       if (level_ysize > preview.ysize)
2910         from_y = (level_ysize - preview.ysize) / 2;
2911     }
2912
2913     from_x += preview.xoffset;
2914     from_y += preview.yoffset;
2915
2916     scroll_direction = MV_RIGHT;
2917     label_state = 1;
2918     label_counter = 0;
2919
2920     DrawPreviewLevelExt(from_x, from_y);
2921     DrawPreviewLevelLabelExt(label_state);
2922
2923     /* initialize delay counters */
2924     DelayReached(&scroll_delay, 0);
2925     DelayReached(&label_delay, 0);
2926
2927     if (leveldir_current->name)
2928     {
2929       struct TextPosInfo *pos = &menu.main.text.level_info_1;
2930       char label_text[MAX_OUTPUT_LINESIZE + 1];
2931 #if 1
2932       int font_nr = pos->font;
2933 #else
2934       int font_nr = FONT_TEXT_1;
2935 #endif
2936 #if 1
2937       int max_len_label_text = getMaxTextLength(pos, font_nr);
2938 #else
2939       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2940 #endif
2941 #if 0
2942       int text_width;
2943       int lxpos, lypos;
2944 #endif
2945
2946 #if 1
2947       if (pos->size != -1)
2948         max_len_label_text = pos->size;
2949 #endif
2950
2951       strncpy(label_text, leveldir_current->name, max_len_label_text);
2952       label_text[max_len_label_text] = '\0';
2953
2954 #if 1
2955       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2956 #else
2957       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2958       lypos = SY + MICROLABEL1_YPOS;
2959
2960       DrawText(lxpos, lypos, label_text, font_nr);
2961 #endif
2962     }
2963
2964     game_status = last_game_status;     /* restore current game status */
2965
2966     return;
2967   }
2968
2969   /* scroll preview level, if needed */
2970   if (preview.anim_mode != ANIM_NONE &&
2971       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2972       DelayReached(&scroll_delay, scroll_delay_value))
2973   {
2974     switch (scroll_direction)
2975     {
2976       case MV_LEFT:
2977         if (from_x > 0)
2978         {
2979           from_x -= preview.step_offset;
2980           from_x = (from_x < 0 ? 0 : from_x);
2981         }
2982         else
2983           scroll_direction = MV_UP;
2984         break;
2985
2986       case MV_RIGHT:
2987         if (from_x < level_xsize - preview.xsize)
2988         {
2989           from_x += preview.step_offset;
2990           from_x = (from_x > level_xsize - preview.xsize ?
2991                     level_xsize - preview.xsize : from_x);
2992         }
2993         else
2994           scroll_direction = MV_DOWN;
2995         break;
2996
2997       case MV_UP:
2998         if (from_y > 0)
2999         {
3000           from_y -= preview.step_offset;
3001           from_y = (from_y < 0 ? 0 : from_y);
3002         }
3003         else
3004           scroll_direction = MV_RIGHT;
3005         break;
3006
3007       case MV_DOWN:
3008         if (from_y < level_ysize - preview.ysize)
3009         {
3010           from_y += preview.step_offset;
3011           from_y = (from_y > level_ysize - preview.ysize ?
3012                     level_ysize - preview.ysize : from_y);
3013         }
3014         else
3015           scroll_direction = MV_LEFT;
3016         break;
3017
3018       default:
3019         break;
3020     }
3021
3022     DrawPreviewLevelExt(from_x, from_y);
3023   }
3024
3025   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3026   /* redraw micro level label, if needed */
3027   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3028       !strEqual(level.author, ANONYMOUS_NAME) &&
3029       !strEqual(level.author, leveldir_current->name) &&
3030       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3031   {
3032     int max_label_counter = 23;
3033
3034     if (leveldir_current->imported_from != NULL &&
3035         strlen(leveldir_current->imported_from) > 0)
3036       max_label_counter += 14;
3037     if (leveldir_current->imported_by != NULL &&
3038         strlen(leveldir_current->imported_by) > 0)
3039       max_label_counter += 14;
3040
3041     label_counter = (label_counter + 1) % max_label_counter;
3042     label_state = (label_counter >= 0 && label_counter <= 7 ?
3043                    MICROLABEL_LEVEL_NAME :
3044                    label_counter >= 9 && label_counter <= 12 ?
3045                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3046                    label_counter >= 14 && label_counter <= 21 ?
3047                    MICROLABEL_LEVEL_AUTHOR :
3048                    label_counter >= 23 && label_counter <= 26 ?
3049                    MICROLABEL_IMPORTED_FROM_HEAD :
3050                    label_counter >= 28 && label_counter <= 35 ?
3051                    MICROLABEL_IMPORTED_FROM :
3052                    label_counter >= 37 && label_counter <= 40 ?
3053                    MICROLABEL_IMPORTED_BY_HEAD :
3054                    label_counter >= 42 && label_counter <= 49 ?
3055                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3056
3057     if (leveldir_current->imported_from == NULL &&
3058         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3059          label_state == MICROLABEL_IMPORTED_FROM))
3060       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3061                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3062
3063     DrawPreviewLevelLabelExt(label_state);
3064   }
3065
3066   game_status = last_game_status;       /* restore current game status */
3067 }
3068
3069 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3070                                     int graphic, int sync_frame, int mask_mode)
3071 {
3072   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3073
3074   if (mask_mode == USE_MASKING)
3075     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3076   else
3077     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3078 }
3079
3080 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3081                                          int graphic, int sync_frame,
3082                                          int mask_mode)
3083 {
3084   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3085
3086   if (mask_mode == USE_MASKING)
3087     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3088   else
3089     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3090 }
3091
3092 inline void DrawGraphicAnimation(int x, int y, int graphic)
3093 {
3094   int lx = LEVELX(x), ly = LEVELY(y);
3095
3096   if (!IN_SCR_FIELD(x, y))
3097     return;
3098
3099 #if NEW_TILESIZE
3100   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3101                           graphic, GfxFrame[lx][ly], NO_MASKING);
3102 #else
3103   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3104                           graphic, GfxFrame[lx][ly], NO_MASKING);
3105 #endif
3106   MarkTileDirty(x, y);
3107 }
3108
3109 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3110 {
3111   int lx = LEVELX(x), ly = LEVELY(y);
3112
3113   if (!IN_SCR_FIELD(x, y))
3114     return;
3115
3116   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3117                           graphic, GfxFrame[lx][ly], NO_MASKING);
3118   MarkTileDirty(x, y);
3119 }
3120
3121 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3122 {
3123   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3124 }
3125
3126 void DrawLevelElementAnimation(int x, int y, int element)
3127 {
3128   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3129
3130   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3131 }
3132
3133 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3134 {
3135   int sx = SCREENX(x), sy = SCREENY(y);
3136
3137   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3138     return;
3139
3140   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3141     return;
3142
3143   DrawGraphicAnimation(sx, sy, graphic);
3144
3145 #if 1
3146   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3147     DrawLevelFieldCrumbled(x, y);
3148 #else
3149   if (GFX_CRUMBLED(Feld[x][y]))
3150     DrawLevelFieldCrumbled(x, y);
3151 #endif
3152 }
3153
3154 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3155 {
3156   int sx = SCREENX(x), sy = SCREENY(y);
3157   int graphic;
3158
3159   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3160     return;
3161
3162   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3163
3164   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3165     return;
3166
3167   DrawGraphicAnimation(sx, sy, graphic);
3168
3169   if (GFX_CRUMBLED(element))
3170     DrawLevelFieldCrumbled(x, y);
3171 }
3172
3173 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3174 {
3175   if (player->use_murphy)
3176   {
3177     /* this works only because currently only one player can be "murphy" ... */
3178     static int last_horizontal_dir = MV_LEFT;
3179     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3180
3181     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3182       last_horizontal_dir = move_dir;
3183
3184     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
3185     {
3186       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3187
3188       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3189     }
3190
3191     return graphic;
3192   }
3193   else
3194     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3195 }
3196
3197 static boolean equalGraphics(int graphic1, int graphic2)
3198 {
3199   struct GraphicInfo *g1 = &graphic_info[graphic1];
3200   struct GraphicInfo *g2 = &graphic_info[graphic2];
3201
3202   return (g1->bitmap      == g2->bitmap &&
3203           g1->src_x       == g2->src_x &&
3204           g1->src_y       == g2->src_y &&
3205           g1->anim_frames == g2->anim_frames &&
3206           g1->anim_delay  == g2->anim_delay &&
3207           g1->anim_mode   == g2->anim_mode);
3208 }
3209
3210 void DrawAllPlayers()
3211 {
3212   int i;
3213
3214   for (i = 0; i < MAX_PLAYERS; i++)
3215     if (stored_player[i].active)
3216       DrawPlayer(&stored_player[i]);
3217 }
3218
3219 void DrawPlayerField(int x, int y)
3220 {
3221   if (!IS_PLAYER(x, y))
3222     return;
3223
3224   DrawPlayer(PLAYERINFO(x, y));
3225 }
3226
3227 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3228
3229 void DrawPlayer(struct PlayerInfo *player)
3230 {
3231   int jx = player->jx;
3232   int jy = player->jy;
3233   int move_dir = player->MovDir;
3234   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3235   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
3236   int last_jx = (player->is_moving ? jx - dx : jx);
3237   int last_jy = (player->is_moving ? jy - dy : jy);
3238   int next_jx = jx + dx;
3239   int next_jy = jy + dy;
3240   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3241   boolean player_is_opaque = FALSE;
3242   int sx = SCREENX(jx), sy = SCREENY(jy);
3243   int sxx = 0, syy = 0;
3244   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3245   int graphic;
3246   int action = ACTION_DEFAULT;
3247   int last_player_graphic = getPlayerGraphic(player, move_dir);
3248   int last_player_frame = player->Frame;
3249   int frame = 0;
3250
3251   /* GfxElement[][] is set to the element the player is digging or collecting;
3252      remove also for off-screen player if the player is not moving anymore */
3253   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3254     GfxElement[jx][jy] = EL_UNDEFINED;
3255
3256   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3257     return;
3258
3259 #if DEBUG
3260   if (!IN_LEV_FIELD(jx, jy))
3261   {
3262     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3263     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3264     printf("DrawPlayerField(): This should never happen!\n");
3265     return;
3266   }
3267 #endif
3268
3269   if (element == EL_EXPLOSION)
3270     return;
3271
3272   action = (player->is_pushing    ? ACTION_PUSHING         :
3273             player->is_digging    ? ACTION_DIGGING         :
3274             player->is_collecting ? ACTION_COLLECTING      :
3275             player->is_moving     ? ACTION_MOVING          :
3276             player->is_snapping   ? ACTION_SNAPPING        :
3277             player->is_dropping   ? ACTION_DROPPING        :
3278             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
3279
3280   if (player->is_waiting)
3281     move_dir = player->dir_waiting;
3282
3283   InitPlayerGfxAnimation(player, action, move_dir);
3284
3285   /* ----------------------------------------------------------------------- */
3286   /* draw things in the field the player is leaving, if needed               */
3287   /* ----------------------------------------------------------------------- */
3288
3289   if (player->is_moving)
3290   {
3291     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3292     {
3293       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3294
3295       if (last_element == EL_DYNAMITE_ACTIVE ||
3296           last_element == EL_EM_DYNAMITE_ACTIVE ||
3297           last_element == EL_SP_DISK_RED_ACTIVE)
3298         DrawDynamite(last_jx, last_jy);
3299       else
3300         DrawLevelFieldThruMask(last_jx, last_jy);
3301     }
3302     else if (last_element == EL_DYNAMITE_ACTIVE ||
3303              last_element == EL_EM_DYNAMITE_ACTIVE ||
3304              last_element == EL_SP_DISK_RED_ACTIVE)
3305       DrawDynamite(last_jx, last_jy);
3306 #if 0
3307     /* !!! this is not enough to prevent flickering of players which are
3308        moving next to each others without a free tile between them -- this
3309        can only be solved by drawing all players layer by layer (first the
3310        background, then the foreground etc.) !!! => TODO */
3311     else if (!IS_PLAYER(last_jx, last_jy))
3312       DrawLevelField(last_jx, last_jy);
3313 #else
3314     else
3315       DrawLevelField(last_jx, last_jy);
3316 #endif
3317
3318     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3319       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3320   }
3321
3322   if (!IN_SCR_FIELD(sx, sy))
3323     return;
3324
3325   /* ----------------------------------------------------------------------- */
3326   /* draw things behind the player, if needed                                */
3327   /* ----------------------------------------------------------------------- */
3328
3329   if (Back[jx][jy])
3330     DrawLevelElement(jx, jy, Back[jx][jy]);
3331   else if (IS_ACTIVE_BOMB(element))
3332     DrawLevelElement(jx, jy, EL_EMPTY);
3333   else
3334   {
3335     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3336     {
3337       int old_element = GfxElement[jx][jy];
3338       int old_graphic = el_act_dir2img(old_element, action, move_dir);
3339       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3340
3341       if (GFX_CRUMBLED(old_element))
3342         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3343       else
3344         DrawGraphic(sx, sy, old_graphic, frame);
3345
3346       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3347         player_is_opaque = TRUE;
3348     }
3349     else
3350     {
3351       GfxElement[jx][jy] = EL_UNDEFINED;
3352
3353       /* make sure that pushed elements are drawn with correct frame rate */
3354 #if 1
3355       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3356
3357       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3358         GfxFrame[jx][jy] = player->StepFrame;
3359 #else
3360       if (player->is_pushing && player->is_moving)
3361         GfxFrame[jx][jy] = player->StepFrame;
3362 #endif
3363
3364       DrawLevelField(jx, jy);
3365     }
3366   }
3367
3368 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3369   /* ----------------------------------------------------------------------- */
3370   /* draw player himself                                                     */
3371   /* ----------------------------------------------------------------------- */
3372
3373   graphic = getPlayerGraphic(player, move_dir);
3374
3375   /* in the case of changed player action or direction, prevent the current
3376      animation frame from being restarted for identical animations */
3377   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3378     player->Frame = last_player_frame;
3379
3380   frame = getGraphicAnimationFrame(graphic, player->Frame);
3381
3382   if (player->GfxPos)
3383   {
3384     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3385       sxx = player->GfxPos;
3386     else
3387       syy = player->GfxPos;
3388   }
3389
3390   if (!setup.soft_scrolling && ScreenMovPos)
3391     sxx = syy = 0;
3392
3393   if (player_is_opaque)
3394     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3395   else
3396     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3397
3398   if (SHIELD_ON(player))
3399   {
3400     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3401                    IMG_SHIELD_NORMAL_ACTIVE);
3402     int frame = getGraphicAnimationFrame(graphic, -1);
3403
3404     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3405   }
3406 #endif
3407
3408 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3409   if (player->GfxPos)
3410   {
3411     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3412       sxx = player->GfxPos;
3413     else
3414       syy = player->GfxPos;
3415   }
3416 #endif
3417
3418   /* ----------------------------------------------------------------------- */
3419   /* draw things the player is pushing, if needed                            */
3420   /* ----------------------------------------------------------------------- */
3421
3422 #if 0
3423   printf("::: %d, %d [%d, %d] [%d]\n",
3424          player->is_pushing, player_is_moving, player->GfxAction,
3425          player->is_moving, player_is_moving);
3426 #endif
3427
3428 #if 1
3429   if (player->is_pushing && player->is_moving)
3430   {
3431     int px = SCREENX(jx), py = SCREENY(jy);
3432     int pxx = (TILEX - ABS(sxx)) * dx;
3433     int pyy = (TILEY - ABS(syy)) * dy;
3434     int gfx_frame = GfxFrame[jx][jy];
3435
3436     int graphic;
3437     int sync_frame;
3438     int frame;
3439
3440     if (!IS_MOVING(jx, jy))             /* push movement already finished */
3441     {
3442       element = Feld[next_jx][next_jy];
3443       gfx_frame = GfxFrame[next_jx][next_jy];
3444     }
3445
3446     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3447
3448 #if 1
3449     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3450     frame = getGraphicAnimationFrame(graphic, sync_frame);
3451 #else
3452     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3453 #endif
3454
3455     /* draw background element under pushed element (like the Sokoban field) */
3456 #if 1
3457     if (game.use_masked_pushing && IS_MOVING(jx, jy))
3458     {
3459       /* this allows transparent pushing animation over non-black background */
3460
3461       if (Back[jx][jy])
3462         DrawLevelElement(jx, jy, Back[jx][jy]);
3463       else
3464         DrawLevelElement(jx, jy, EL_EMPTY);
3465
3466       if (Back[next_jx][next_jy])
3467         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3468       else
3469         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3470     }
3471     else if (Back[next_jx][next_jy])
3472       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3473 #else
3474     if (Back[next_jx][next_jy])
3475       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3476 #endif
3477
3478 #if 0
3479     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3480            jx, px, player->GfxPos, player->StepFrame,
3481            player->is_pushing,
3482            dx, sxx, pxx,
3483            IS_MOVING(jx, jy),
3484            graphic, frame,
3485            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3486 #endif
3487
3488 #if 1
3489     /* do not draw (EM style) pushing animation when pushing is finished */
3490     /* (two-tile animations usually do not contain start and end frame) */
3491     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3492       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3493     else
3494       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3495 #else
3496     /* masked drawing is needed for EMC style (double) movement graphics */
3497     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3498     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3499 #endif
3500   }
3501 #endif
3502
3503 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3504   /* ----------------------------------------------------------------------- */
3505   /* draw player himself                                                     */
3506   /* ----------------------------------------------------------------------- */
3507
3508   graphic = getPlayerGraphic(player, move_dir);
3509
3510   /* in the case of changed player action or direction, prevent the current
3511      animation frame from being restarted for identical animations */
3512   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3513     player->Frame = last_player_frame;
3514
3515   frame = getGraphicAnimationFrame(graphic, player->Frame);
3516
3517   if (player->GfxPos)
3518   {
3519     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3520       sxx = player->GfxPos;
3521     else
3522       syy = player->GfxPos;
3523   }
3524
3525   if (!setup.soft_scrolling && ScreenMovPos)
3526     sxx = syy = 0;
3527
3528   if (player_is_opaque)
3529     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3530   else
3531     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3532
3533   if (SHIELD_ON(player))
3534   {
3535     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3536                    IMG_SHIELD_NORMAL_ACTIVE);
3537     int frame = getGraphicAnimationFrame(graphic, -1);
3538
3539     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3540   }
3541 #endif
3542
3543   /* ----------------------------------------------------------------------- */
3544   /* draw things in front of player (active dynamite or dynabombs)           */
3545   /* ----------------------------------------------------------------------- */
3546
3547   if (IS_ACTIVE_BOMB(element))
3548   {
3549     graphic = el2img(element);
3550     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3551
3552     if (game.emulation == EMU_SUPAPLEX)
3553       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3554     else
3555       DrawGraphicThruMask(sx, sy, graphic, frame);
3556   }
3557
3558   if (player_is_moving && last_element == EL_EXPLOSION)
3559   {
3560     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3561                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
3562     int graphic = el_act2img(element, ACTION_EXPLODING);
3563     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3564     int phase = ExplodePhase[last_jx][last_jy] - 1;
3565     int frame = getGraphicAnimationFrame(graphic, phase - delay);
3566
3567     if (phase >= delay)
3568       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3569   }
3570
3571   /* ----------------------------------------------------------------------- */
3572   /* draw elements the player is just walking/passing through/under          */
3573   /* ----------------------------------------------------------------------- */
3574
3575   if (player_is_moving)
3576   {
3577     /* handle the field the player is leaving ... */
3578     if (IS_ACCESSIBLE_INSIDE(last_element))
3579       DrawLevelField(last_jx, last_jy);
3580     else if (IS_ACCESSIBLE_UNDER(last_element))
3581       DrawLevelFieldThruMask(last_jx, last_jy);
3582   }
3583
3584   /* do not redraw accessible elements if the player is just pushing them */
3585   if (!player_is_moving || !player->is_pushing)
3586   {
3587     /* ... and the field the player is entering */
3588     if (IS_ACCESSIBLE_INSIDE(element))
3589       DrawLevelField(jx, jy);
3590     else if (IS_ACCESSIBLE_UNDER(element))
3591       DrawLevelFieldThruMask(jx, jy);
3592   }
3593
3594   MarkTileDirty(sx, sy);
3595 }
3596
3597 /* ------------------------------------------------------------------------- */
3598
3599 void WaitForEventToContinue()
3600 {
3601   boolean still_wait = TRUE;
3602
3603   /* simulate releasing mouse button over last gadget, if still pressed */
3604   if (button_status)
3605     HandleGadgets(-1, -1, 0);
3606
3607   button_status = MB_RELEASED;
3608
3609 #if 1
3610   ClearEventQueue();
3611 #endif
3612
3613   while (still_wait)
3614   {
3615     if (PendingEvent())
3616     {
3617       Event event;
3618
3619       NextEvent(&event);
3620
3621       switch (event.type)
3622       {
3623         case EVENT_BUTTONPRESS:
3624         case EVENT_KEYPRESS:
3625           still_wait = FALSE;
3626           break;
3627
3628         case EVENT_KEYRELEASE:
3629           ClearPlayerAction();
3630           break;
3631
3632         default:
3633           HandleOtherEvents(&event);
3634           break;
3635       }
3636     }
3637     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3638     {
3639       still_wait = FALSE;
3640     }
3641
3642     DoAnimation();
3643
3644     /* don't eat all CPU time */
3645     Delay(10);
3646   }
3647 }
3648
3649 #define MAX_REQUEST_LINES               13
3650 #define MAX_REQUEST_LINE_FONT1_LEN      7
3651 #define MAX_REQUEST_LINE_FONT2_LEN      10
3652
3653 boolean Request(char *text, unsigned int req_state)
3654 {
3655   int mx, my, ty, result = -1;
3656   unsigned int old_door_state;
3657   int last_game_status = game_status;   /* save current game status */
3658   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3659   int font_nr = FONT_TEXT_2;
3660 #if 0
3661   int max_word_len = 0;
3662 #endif
3663   char *text_ptr;
3664   int i;
3665
3666 #if 1
3667   global.use_envelope_request = 0;
3668 #endif
3669
3670 #if 1
3671   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3672   {
3673     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3674     font_nr = FONT_TEXT_1;
3675   }
3676 #else
3677   for (text_ptr = text; *text_ptr; text_ptr++)
3678   {
3679     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3680
3681     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3682     {
3683       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3684 #if 1
3685       font_nr = FONT_TEXT_1;
3686 #else
3687       font_nr = FONT_LEVEL_NUMBER;
3688 #endif
3689
3690       break;
3691     }
3692   }
3693 #endif
3694
3695   if (game_status == GAME_MODE_PLAYING)
3696   {
3697     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3698       BlitScreenToBitmap_EM(backbuffer);
3699     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3700       BlitScreenToBitmap_SP(backbuffer);
3701   }
3702
3703   /* disable deactivated drawing when quick-loading level tape recording */
3704   if (tape.playing && tape.deactivate_display)
3705     TapeDeactivateDisplayOff(TRUE);
3706
3707   SetMouseCursor(CURSOR_DEFAULT);
3708
3709 #if defined(NETWORK_AVALIABLE)
3710   /* pause network game while waiting for request to answer */
3711   if (options.network &&
3712       game_status == GAME_MODE_PLAYING &&
3713       req_state & REQUEST_WAIT_FOR_INPUT)
3714     SendToServer_PausePlaying();
3715 #endif
3716
3717   old_door_state = GetDoorState();
3718
3719   /* simulate releasing mouse button over last gadget, if still pressed */
3720   if (button_status)
3721     HandleGadgets(-1, -1, 0);
3722
3723   UnmapAllGadgets();
3724
3725   /* draw released gadget before proceeding */
3726   // BackToFront();
3727
3728 #if 0
3729   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3730 #else
3731   if (old_door_state & DOOR_OPEN_1)
3732 #endif
3733   {
3734 #if 1
3735     if (!global.use_envelope_request)
3736       CloseDoor(DOOR_CLOSE_1);
3737 #else
3738     CloseDoor(DOOR_CLOSE_1);
3739 #endif
3740
3741     /* save old door content */
3742     BlitBitmap(bitmap_db_door, bitmap_db_door,
3743                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3744                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3745   }
3746
3747 #if 1
3748   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3749 #endif
3750
3751   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3752
3753   /* clear door drawing field */
3754   DrawBackground(DX, DY, DXSIZE, DYSIZE);
3755
3756   /* force DOOR font inside door area */
3757   game_status = GAME_MODE_PSEUDO_DOOR;
3758
3759   /* write text for request */
3760   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3761   {
3762     char text_line[max_request_line_len + 1];
3763     int tx, tl, tc = 0;
3764
3765     if (!*text_ptr)
3766       break;
3767
3768     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3769     {
3770       tc = *(text_ptr + tx);
3771       if (!tc || tc == ' ')
3772         break;
3773     }
3774
3775     if (!tl)
3776     { 
3777       text_ptr++; 
3778       ty--; 
3779       continue; 
3780     }
3781
3782     strncpy(text_line, text_ptr, tl);
3783     text_line[tl] = 0;
3784
3785     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3786              DY + 8 + ty * (getFontHeight(font_nr) + 2),
3787              text_line, font_nr);
3788
3789     text_ptr += tl + (tc == ' ' ? 1 : 0);
3790   }
3791
3792   game_status = last_game_status;       /* restore current game status */
3793
3794 #if 1
3795   if (global.use_envelope_request)
3796   {
3797     /* !!! TMP !!! */
3798     FreeToolButtons();
3799     CreateToolButtons();
3800   }
3801 #endif
3802
3803   if (req_state & REQ_ASK)
3804   {
3805     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3806     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3807   }
3808   else if (req_state & REQ_CONFIRM)
3809   {
3810     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3811   }
3812   else if (req_state & REQ_PLAYER)
3813   {
3814     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3815     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3816     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3817     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3818   }
3819
3820   /* copy request gadgets to door backbuffer */
3821   BlitBitmap(drawto, bitmap_db_door,
3822              DX, DY, DXSIZE, DYSIZE,
3823              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3824
3825 #if 1
3826   if (global.use_envelope_request)
3827   {
3828     ShowEnvelopeDoor(text, ACTION_OPENING);
3829
3830     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3831     {
3832       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3833                                    i == TOOL_CTRL_ID_NO)) ||
3834           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3835           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3836                                       i == TOOL_CTRL_ID_PLAYER_2 &&
3837                                       i == TOOL_CTRL_ID_PLAYER_3 &&
3838                                       i == TOOL_CTRL_ID_PLAYER_4)))
3839       {
3840         int x = tool_gadget[i]->x + dDX;
3841         int y = tool_gadget[i]->y + dDY;
3842
3843         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3844       }
3845     }
3846   }
3847 #endif
3848
3849 #if 1
3850   if (!global.use_envelope_request)
3851     OpenDoor(DOOR_OPEN_1);
3852 #else
3853   OpenDoor(DOOR_OPEN_1);
3854 #endif
3855
3856   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3857   {
3858     if (game_status == GAME_MODE_PLAYING)
3859     {
3860       SetPanelBackground();
3861       SetDrawBackgroundMask(REDRAW_DOOR_1);
3862     }
3863     else
3864     {
3865       SetDrawBackgroundMask(REDRAW_FIELD);
3866     }
3867
3868     return FALSE;
3869   }
3870
3871 #if 1
3872   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3873     InitAnimation();
3874 #else
3875   if (game_status != GAME_MODE_MAIN)
3876     InitAnimation();
3877 #endif
3878
3879   button_status = MB_RELEASED;
3880
3881   request_gadget_id = -1;
3882
3883   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3884
3885   while (result < 0)
3886   {
3887     if (PendingEvent())
3888     {
3889       Event event;
3890
3891       NextEvent(&event);
3892
3893       switch (event.type)
3894       {
3895         case EVENT_BUTTONPRESS:
3896         case EVENT_BUTTONRELEASE:
3897         case EVENT_MOTIONNOTIFY:
3898         {
3899           if (event.type == EVENT_MOTIONNOTIFY)
3900           {
3901             if (!PointerInWindow(window))
3902               continue; /* window and pointer are on different screens */
3903
3904             if (!button_status)
3905               continue;
3906
3907             motion_status = TRUE;
3908             mx = ((MotionEvent *) &event)->x;
3909             my = ((MotionEvent *) &event)->y;
3910           }
3911           else
3912           {
3913             motion_status = FALSE;
3914             mx = ((ButtonEvent *) &event)->x;
3915             my = ((ButtonEvent *) &event)->y;
3916             if (event.type == EVENT_BUTTONPRESS)
3917               button_status = ((ButtonEvent *) &event)->button;
3918             else
3919               button_status = MB_RELEASED;
3920           }
3921
3922           /* this sets 'request_gadget_id' */
3923           HandleGadgets(mx, my, button_status);
3924
3925           switch (request_gadget_id)
3926           {
3927             case TOOL_CTRL_ID_YES:
3928               result = TRUE;
3929               break;
3930             case TOOL_CTRL_ID_NO:
3931               result = FALSE;
3932               break;
3933             case TOOL_CTRL_ID_CONFIRM:
3934               result = TRUE | FALSE;
3935               break;
3936
3937             case TOOL_CTRL_ID_PLAYER_1:
3938               result = 1;
3939               break;
3940             case TOOL_CTRL_ID_PLAYER_2:
3941               result = 2;
3942               break;
3943             case TOOL_CTRL_ID_PLAYER_3:
3944               result = 3;
3945               break;
3946             case TOOL_CTRL_ID_PLAYER_4:
3947               result = 4;
3948               break;
3949
3950             default:
3951               break;
3952           }
3953
3954           break;
3955         }
3956
3957         case EVENT_KEYPRESS:
3958           switch (GetEventKey((KeyEvent *)&event, TRUE))
3959           {
3960             case KSYM_space:
3961               if (req_state & REQ_CONFIRM)
3962                 result = 1;
3963               break;
3964
3965             case KSYM_Return:
3966               result = 1;
3967               break;
3968
3969             case KSYM_Escape:
3970               result = 0;
3971               break;
3972
3973             default:
3974               break;
3975           }
3976
3977           if (req_state & REQ_PLAYER)
3978             result = 0;
3979           break;
3980
3981         case EVENT_KEYRELEASE:
3982           ClearPlayerAction();
3983           break;
3984
3985         default:
3986           HandleOtherEvents(&event);
3987           break;
3988       }
3989     }
3990     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3991     {
3992       int joy = AnyJoystick();
3993
3994       if (joy & JOY_BUTTON_1)
3995         result = 1;
3996       else if (joy & JOY_BUTTON_2)
3997         result = 0;
3998     }
3999
4000 #if 1
4001
4002     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4003     {
4004       HandleGameActions();
4005     }
4006     else
4007     {
4008       DoAnimation();
4009
4010       if (!PendingEvent())      /* delay only if no pending events */
4011         Delay(10);
4012     }
4013
4014 #if 1
4015     game_status = GAME_MODE_PSEUDO_DOOR;
4016 #endif
4017
4018     BackToFront();
4019
4020 #if 1
4021     game_status = last_game_status;     /* restore current game status */
4022 #endif
4023
4024 #else
4025
4026     DoAnimation();
4027
4028 #if 1
4029     if (!PendingEvent())        /* delay only if no pending events */
4030       Delay(10);
4031 #else
4032     /* don't eat all CPU time */
4033     Delay(10);
4034 #endif
4035
4036 #endif
4037   }
4038
4039   if (game_status != GAME_MODE_MAIN)
4040     StopAnimation();
4041
4042   UnmapToolButtons();
4043
4044 #if 1
4045   if (global.use_envelope_request)
4046     ShowEnvelopeDoor(text, ACTION_CLOSING);
4047 #endif
4048
4049 #if 1
4050   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4051 #else
4052   if (!(req_state & REQ_STAY_OPEN))
4053 #endif
4054   {
4055     CloseDoor(DOOR_CLOSE_1);
4056
4057     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4058         (req_state & REQ_REOPEN))
4059       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4060   }
4061
4062   RemapAllGadgets();
4063
4064   if (game_status == GAME_MODE_PLAYING)
4065   {
4066     SetPanelBackground();
4067     SetDrawBackgroundMask(REDRAW_DOOR_1);
4068   }
4069   else
4070   {
4071     SetDrawBackgroundMask(REDRAW_FIELD);
4072   }
4073
4074 #if defined(NETWORK_AVALIABLE)
4075   /* continue network game after request */
4076   if (options.network &&
4077       game_status == GAME_MODE_PLAYING &&
4078       req_state & REQUEST_WAIT_FOR_INPUT)
4079     SendToServer_ContinuePlaying();
4080 #endif
4081
4082   /* restore deactivated drawing when quick-loading level tape recording */
4083   if (tape.playing && tape.deactivate_display)
4084     TapeDeactivateDisplayOn();
4085
4086   return result;
4087 }
4088
4089 unsigned int OpenDoor(unsigned int door_state)
4090 {
4091   if (door_state & DOOR_COPY_BACK)
4092   {
4093     if (door_state & DOOR_OPEN_1)
4094       BlitBitmap(bitmap_db_door, bitmap_db_door,
4095                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4096                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4097
4098     if (door_state & DOOR_OPEN_2)
4099       BlitBitmap(bitmap_db_door, bitmap_db_door,
4100                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4101                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4102
4103     door_state &= ~DOOR_COPY_BACK;
4104   }
4105
4106   return MoveDoor(door_state);
4107 }
4108
4109 unsigned int CloseDoor(unsigned int door_state)
4110 {
4111   unsigned int old_door_state = GetDoorState();
4112
4113   if (!(door_state & DOOR_NO_COPY_BACK))
4114   {
4115     if (old_door_state & DOOR_OPEN_1)
4116       BlitBitmap(backbuffer, bitmap_db_door,
4117                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4118
4119     if (old_door_state & DOOR_OPEN_2)
4120       BlitBitmap(backbuffer, bitmap_db_door,
4121                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4122
4123     door_state &= ~DOOR_NO_COPY_BACK;
4124   }
4125
4126   return MoveDoor(door_state);
4127 }
4128
4129 unsigned int GetDoorState()
4130 {
4131   return MoveDoor(DOOR_GET_STATE);
4132 }
4133
4134 unsigned int SetDoorState(unsigned int door_state)
4135 {
4136   return MoveDoor(door_state | DOOR_SET_STATE);
4137 }
4138
4139 unsigned int MoveDoor(unsigned int door_state)
4140 {
4141   static int door1 = DOOR_OPEN_1;
4142   static int door2 = DOOR_CLOSE_2;
4143   unsigned long door_delay = 0;
4144   unsigned long door_delay_value;
4145   int stepsize = 1;
4146
4147   if (door_1.width < 0 || door_1.width > DXSIZE)
4148     door_1.width = DXSIZE;
4149   if (door_1.height < 0 || door_1.height > DYSIZE)
4150     door_1.height = DYSIZE;
4151   if (door_2.width < 0 || door_2.width > VXSIZE)
4152     door_2.width = VXSIZE;
4153   if (door_2.height < 0 || door_2.height > VYSIZE)
4154     door_2.height = VYSIZE;
4155
4156   if (door_state == DOOR_GET_STATE)
4157     return (door1 | door2);
4158
4159   if (door_state & DOOR_SET_STATE)
4160   {
4161     if (door_state & DOOR_ACTION_1)
4162       door1 = door_state & DOOR_ACTION_1;
4163     if (door_state & DOOR_ACTION_2)
4164       door2 = door_state & DOOR_ACTION_2;
4165
4166     return (door1 | door2);
4167   }
4168
4169   if (!(door_state & DOOR_FORCE_REDRAW))
4170   {
4171     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4172       door_state &= ~DOOR_OPEN_1;
4173     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4174       door_state &= ~DOOR_CLOSE_1;
4175     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4176       door_state &= ~DOOR_OPEN_2;
4177     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4178       door_state &= ~DOOR_CLOSE_2;
4179   }
4180
4181   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4182                       door_2.step_delay);
4183
4184   if (setup.quick_doors)
4185   {
4186     stepsize = 20;              /* must be chosen to always draw last frame */
4187     door_delay_value = 0;
4188   }
4189
4190   if (global.autoplay_leveldir)
4191   {
4192     door_state |= DOOR_NO_DELAY;
4193     door_state &= ~DOOR_CLOSE_ALL;
4194   }
4195
4196 #if 1
4197   if (game_status == GAME_MODE_EDITOR)
4198     door_state |= DOOR_NO_DELAY;
4199 #endif
4200
4201   if (door_state & DOOR_ACTION)
4202   {
4203     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4204     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4205     boolean door_1_done = (!handle_door_1);
4206     boolean door_2_done = (!handle_door_2);
4207     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4208     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4209     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4210     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4211     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4212     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4213     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
4214     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4215     int door_skip = max_door_size - door_size;
4216     int end = door_size;
4217     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4218     int k;
4219
4220     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4221     {
4222       /* opening door sound has priority over simultaneously closing door */
4223       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4224         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4225       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4226         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4227     }
4228
4229     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4230     {
4231       int x = k;
4232       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4233       GC gc = bitmap->stored_clip_gc;
4234
4235       if (door_state & DOOR_ACTION_1)
4236       {
4237         int a = MIN(x * door_1.step_offset, end);
4238         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4239         int i = p + door_skip;
4240
4241         if (door_1.anim_mode & ANIM_STATIC_PANEL)
4242         {
4243           BlitBitmap(bitmap_db_door, drawto,
4244                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4245                      DXSIZE, DYSIZE, DX, DY);
4246         }
4247         else if (x <= a)
4248         {
4249           BlitBitmap(bitmap_db_door, drawto,
4250                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4251                      DXSIZE, DYSIZE - p / 2, DX, DY);
4252
4253           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4254         }
4255
4256         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4257         {
4258           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4259           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4260           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
4261           int dst2_x = DX,              dst2_y = DY;
4262           int width = i, height = DYSIZE;
4263
4264           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4265           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4266                            dst1_x, dst1_y);
4267
4268           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4269           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4270                            dst2_x, dst2_y);
4271         }
4272         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4273         {
4274           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4275           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
4276           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4277           int dst2_x = DX,              dst2_y = DY;
4278           int width = DXSIZE, height = i;
4279
4280           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4281           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4282                            dst1_x, dst1_y);
4283
4284           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4285           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4286                            dst2_x, dst2_y);
4287         }
4288         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
4289         {
4290           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4291
4292           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4293           BlitBitmapMasked(bitmap, drawto,
4294                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4295                            DX + DXSIZE - i, DY + j);
4296           BlitBitmapMasked(bitmap, drawto,
4297                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4298                            DX + DXSIZE - i, DY + 140 + j);
4299           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4300                         DY - (DOOR_GFX_PAGEY1 + j));
4301           BlitBitmapMasked(bitmap, drawto,
4302                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4303                            DX, DY);
4304           BlitBitmapMasked(bitmap, drawto,
4305                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4306                            DX, DY + 140 - j);
4307
4308           BlitBitmapMasked(bitmap, drawto,
4309                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4310                            DX, DY + 77 - j);
4311           BlitBitmapMasked(bitmap, drawto,
4312                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4313                            DX, DY + 203 - j);
4314           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4315           BlitBitmapMasked(bitmap, drawto,
4316                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4317                            DX + DXSIZE - i, DY + 77 + j);
4318           BlitBitmapMasked(bitmap, drawto,
4319                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4320                            DX + DXSIZE - i, DY + 203 + j);
4321         }
4322
4323         redraw_mask |= REDRAW_DOOR_1;
4324         door_1_done = (a == end);
4325       }
4326
4327       if (door_state & DOOR_ACTION_2)
4328       {
4329         int a = MIN(x * door_2.step_offset, door_size);
4330         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4331         int i = p + door_skip;
4332
4333         if (door_2.anim_mode & ANIM_STATIC_PANEL)
4334         {
4335           BlitBitmap(bitmap_db_door, drawto,
4336                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4337                      VXSIZE, VYSIZE, VX, VY);
4338         }
4339         else if (x <= VYSIZE)
4340         {
4341           BlitBitmap(bitmap_db_door, drawto,
4342                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4343                      VXSIZE, VYSIZE - p / 2, VX, VY);
4344
4345           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4346         }
4347
4348         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4349         {
4350           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4351           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4352           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
4353           int dst2_x = VX,              dst2_y = VY;
4354           int width = i, height = VYSIZE;
4355
4356           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4357           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4358                            dst1_x, dst1_y);
4359
4360           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4361           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4362                            dst2_x, dst2_y);
4363         }
4364         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4365         {
4366           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4367           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
4368           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4369           int dst2_x = VX,              dst2_y = VY;
4370           int width = VXSIZE, height = i;
4371
4372           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4373           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4374                            dst1_x, dst1_y);
4375
4376           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4377           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4378                            dst2_x, dst2_y);
4379         }
4380         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
4381         {
4382           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4383
4384           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4385           BlitBitmapMasked(bitmap, drawto,
4386                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4387                            VX + VXSIZE - i, VY + j);
4388           SetClipOrigin(bitmap, gc,
4389                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4390           BlitBitmapMasked(bitmap, drawto,
4391                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4392                            VX, VY);
4393
4394           BlitBitmapMasked(bitmap, drawto,
4395                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4396                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4397           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4398           BlitBitmapMasked(bitmap, drawto,
4399                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4400                            i, VYSIZE / 2 - j,
4401                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4402         }
4403
4404         redraw_mask |= REDRAW_DOOR_2;
4405         door_2_done = (a == VXSIZE);
4406       }
4407
4408       if (!(door_state & DOOR_NO_DELAY))
4409       {
4410         BackToFront();
4411
4412         if (game_status == GAME_MODE_MAIN)
4413           DoAnimation();
4414
4415         WaitUntilDelayReached(&door_delay, door_delay_value);
4416       }
4417     }
4418   }
4419
4420   if (door_state & DOOR_ACTION_1)
4421     door1 = door_state & DOOR_ACTION_1;
4422   if (door_state & DOOR_ACTION_2)
4423     door2 = door_state & DOOR_ACTION_2;
4424
4425   return (door1 | door2);
4426 }
4427
4428 void DrawSpecialEditorDoor()
4429 {
4430   /* draw bigger toolbox window */
4431   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4432              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4433              EX - 4, EY - 12);
4434   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4435              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4436              EX - 6, EY - 4);
4437
4438   redraw_mask |= REDRAW_ALL;
4439 }
4440
4441 void UndrawSpecialEditorDoor()
4442 {
4443   /* draw normal tape recorder window */
4444   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4445              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4446              EX - 6, EY - 12);
4447
4448   redraw_mask |= REDRAW_ALL;
4449 }
4450
4451
4452 /* ---------- new tool button stuff ---------------------------------------- */
4453
4454 /* graphic position values for tool buttons */
4455 #define TOOL_BUTTON_YES_XPOS            2
4456 #define TOOL_BUTTON_YES_YPOS            250
4457 #define TOOL_BUTTON_YES_GFX_YPOS        0
4458 #define TOOL_BUTTON_YES_XSIZE           46
4459 #define TOOL_BUTTON_YES_YSIZE           28
4460 #define TOOL_BUTTON_NO_XPOS             52
4461 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
4462 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
4463 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
4464 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
4465 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
4466 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
4467 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
4468 #define TOOL_BUTTON_CONFIRM_XSIZE       96
4469 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
4470 #define TOOL_BUTTON_PLAYER_XSIZE        30
4471 #define TOOL_BUTTON_PLAYER_YSIZE        30
4472 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
4473 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
4474 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4475 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4476 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4477                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4478 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4479                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4480 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4481                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4482 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4483                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4484 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4485                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4486 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4487                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4488 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4489                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4490 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4491                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4492
4493 static struct
4494 {
4495   int xpos, ypos;
4496   int x, y;
4497   int width, height;
4498   int gadget_id;
4499   char *infotext;
4500 } toolbutton_info[NUM_TOOL_BUTTONS] =
4501 {
4502   {
4503     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
4504     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
4505     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
4506     TOOL_CTRL_ID_YES,
4507     "yes"
4508   },
4509   {
4510     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
4511     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
4512     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
4513     TOOL_CTRL_ID_NO,
4514     "no"
4515   },
4516   {
4517     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
4518     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
4519     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
4520     TOOL_CTRL_ID_CONFIRM,
4521     "confirm"
4522   },
4523   {
4524     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4525     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
4526     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4527     TOOL_CTRL_ID_PLAYER_1,
4528     "player 1"
4529   },
4530   {
4531     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4532     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
4533     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4534     TOOL_CTRL_ID_PLAYER_2,
4535     "player 2"
4536   },
4537   {
4538     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4539     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
4540     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4541     TOOL_CTRL_ID_PLAYER_3,
4542     "player 3"
4543   },
4544   {
4545     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4546     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
4547     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4548     TOOL_CTRL_ID_PLAYER_4,
4549     "player 4"
4550   }
4551 };
4552
4553 void CreateToolButtons()
4554 {
4555   int i;
4556
4557   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4558   {
4559     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4560     Bitmap *deco_bitmap = None;
4561     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4562     struct GadgetInfo *gi;
4563     unsigned long event_mask;
4564     int gd_xoffset, gd_yoffset;
4565     int gd_x1, gd_x2, gd_y;
4566     int id = i;
4567
4568     event_mask = GD_EVENT_RELEASED;
4569
4570     gd_xoffset = toolbutton_info[i].xpos;
4571     gd_yoffset = toolbutton_info[i].ypos;
4572     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4573     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4574     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4575
4576     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4577     {
4578       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4579
4580       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4581                            &deco_bitmap, &deco_x, &deco_y);
4582       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4583       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4584     }
4585
4586     gi = CreateGadget(GDI_CUSTOM_ID, id,
4587                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4588                       GDI_X, DX + toolbutton_info[i].x,
4589                       GDI_Y, DY + toolbutton_info[i].y,
4590                       GDI_WIDTH, toolbutton_info[i].width,
4591                       GDI_HEIGHT, toolbutton_info[i].height,
4592                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4593                       GDI_STATE, GD_BUTTON_UNPRESSED,
4594                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4595                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4596                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4597                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4598                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4599                       GDI_DECORATION_SHIFTING, 1, 1,
4600                       GDI_DIRECT_DRAW, FALSE,
4601                       GDI_EVENT_MASK, event_mask,
4602                       GDI_CALLBACK_ACTION, HandleToolButtons,
4603                       GDI_END);
4604
4605     if (gi == NULL)
4606       Error(ERR_EXIT, "cannot create gadget");
4607
4608     tool_gadget[id] = gi;
4609   }
4610 }
4611
4612 void FreeToolButtons()
4613 {
4614   int i;
4615
4616   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4617     FreeGadget(tool_gadget[i]);
4618 }
4619
4620 static void UnmapToolButtons()
4621 {
4622   int i;
4623
4624   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4625     UnmapGadget(tool_gadget[i]);
4626 }
4627
4628 static void HandleToolButtons(struct GadgetInfo *gi)
4629 {
4630   request_gadget_id = gi->custom_id;
4631 }
4632
4633 static struct Mapping_EM_to_RND_object
4634 {
4635   int element_em;
4636   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
4637   boolean is_backside;                  /* backside of moving element */
4638
4639   int element_rnd;
4640   int action;
4641   int direction;
4642 }
4643 em_object_mapping_list[] =
4644 {
4645   {
4646     Xblank,                             TRUE,   FALSE,
4647     EL_EMPTY,                           -1, -1
4648   },
4649   {
4650     Yacid_splash_eB,                    FALSE,  FALSE,
4651     EL_ACID_SPLASH_RIGHT,               -1, -1
4652   },
4653   {
4654     Yacid_splash_wB,                    FALSE,  FALSE,
4655     EL_ACID_SPLASH_LEFT,                -1, -1
4656   },
4657
4658 #ifdef EM_ENGINE_BAD_ROLL
4659   {
4660     Xstone_force_e,                     FALSE,  FALSE,
4661     EL_ROCK,                            -1, MV_BIT_RIGHT
4662   },
4663   {
4664     Xstone_force_w,                     FALSE,  FALSE,
4665     EL_ROCK,                            -1, MV_BIT_LEFT
4666   },
4667   {
4668     Xnut_force_e,                       FALSE,  FALSE,
4669     EL_NUT,                             -1, MV_BIT_RIGHT
4670   },
4671   {
4672     Xnut_force_w,                       FALSE,  FALSE,
4673     EL_NUT,                             -1, MV_BIT_LEFT
4674   },
4675   {
4676     Xspring_force_e,                    FALSE,  FALSE,
4677     EL_SPRING,                          -1, MV_BIT_RIGHT
4678   },
4679   {
4680     Xspring_force_w,                    FALSE,  FALSE,
4681     EL_SPRING,                          -1, MV_BIT_LEFT
4682   },
4683   {
4684     Xemerald_force_e,                   FALSE,  FALSE,
4685     EL_EMERALD,                         -1, MV_BIT_RIGHT
4686   },
4687   {
4688     Xemerald_force_w,                   FALSE,  FALSE,
4689     EL_EMERALD,                         -1, MV_BIT_LEFT
4690   },
4691   {
4692     Xdiamond_force_e,                   FALSE,  FALSE,
4693     EL_DIAMOND,                         -1, MV_BIT_RIGHT
4694   },
4695   {
4696     Xdiamond_force_w,                   FALSE,  FALSE,
4697     EL_DIAMOND,                         -1, MV_BIT_LEFT
4698   },
4699   {
4700     Xbomb_force_e,                      FALSE,  FALSE,
4701     EL_BOMB,                            -1, MV_BIT_RIGHT
4702   },
4703   {
4704     Xbomb_force_w,                      FALSE,  FALSE,
4705     EL_BOMB,                            -1, MV_BIT_LEFT
4706   },
4707 #endif  /* EM_ENGINE_BAD_ROLL */
4708
4709   {
4710     Xstone,                             TRUE,   FALSE,
4711     EL_ROCK,                            -1, -1
4712   },
4713   {
4714     Xstone_pause,                       FALSE,  FALSE,
4715     EL_ROCK,                            -1, -1
4716   },
4717   {
4718     Xstone_fall,                        FALSE,  FALSE,
4719     EL_ROCK,                            -1, -1
4720   },
4721   {
4722     Ystone_s,                           FALSE,  FALSE,
4723     EL_ROCK,                            ACTION_FALLING, -1
4724   },
4725   {
4726     Ystone_sB,                          FALSE,  TRUE,
4727     EL_ROCK,                            ACTION_FALLING, -1
4728   },
4729   {
4730     Ystone_e,                           FALSE,  FALSE,
4731     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4732   },
4733   {
4734     Ystone_eB,                          FALSE,  TRUE,
4735     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4736   },
4737   {
4738     Ystone_w,                           FALSE,  FALSE,
4739     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4740   },
4741   {
4742     Ystone_wB,                          FALSE,  TRUE,
4743     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4744   },
4745   {
4746     Xnut,                               TRUE,   FALSE,
4747     EL_NUT,                             -1, -1
4748   },
4749   {
4750     Xnut_pause,                         FALSE,  FALSE,
4751     EL_NUT,                             -1, -1
4752   },
4753   {
4754     Xnut_fall,                          FALSE,  FALSE,
4755     EL_NUT,                             -1, -1
4756   },
4757   {
4758     Ynut_s,                             FALSE,  FALSE,
4759     EL_NUT,                             ACTION_FALLING, -1
4760   },
4761   {
4762     Ynut_sB,                            FALSE,  TRUE,
4763     EL_NUT,                             ACTION_FALLING, -1
4764   },
4765   {
4766     Ynut_e,                             FALSE,  FALSE,
4767     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4768   },
4769   {
4770     Ynut_eB,                            FALSE,  TRUE,
4771     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4772   },
4773   {
4774     Ynut_w,                             FALSE,  FALSE,
4775     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4776   },
4777   {
4778     Ynut_wB,                            FALSE,  TRUE,
4779     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4780   },
4781   {
4782     Xbug_n,                             TRUE,   FALSE,
4783     EL_BUG_UP,                          -1, -1
4784   },
4785   {
4786     Xbug_e,                             TRUE,   FALSE,
4787     EL_BUG_RIGHT,                       -1, -1
4788   },
4789   {
4790     Xbug_s,                             TRUE,   FALSE,
4791     EL_BUG_DOWN,                        -1, -1
4792   },
4793   {
4794     Xbug_w,                             TRUE,   FALSE,
4795     EL_BUG_LEFT,                        -1, -1
4796   },
4797   {
4798     Xbug_gon,                           FALSE,  FALSE,
4799     EL_BUG_UP,                          -1, -1
4800   },
4801   {
4802     Xbug_goe,                           FALSE,  FALSE,
4803     EL_BUG_RIGHT,                       -1, -1
4804   },
4805   {
4806     Xbug_gos,                           FALSE,  FALSE,
4807     EL_BUG_DOWN,                        -1, -1
4808   },
4809   {
4810     Xbug_gow,                           FALSE,  FALSE,
4811     EL_BUG_LEFT,                        -1, -1
4812   },
4813   {
4814     Ybug_n,                             FALSE,  FALSE,
4815     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4816   },
4817   {
4818     Ybug_nB,                            FALSE,  TRUE,
4819     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4820   },
4821   {
4822     Ybug_e,                             FALSE,  FALSE,
4823     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4824   },
4825   {
4826     Ybug_eB,                            FALSE,  TRUE,
4827     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4828   },
4829   {
4830     Ybug_s,                             FALSE,  FALSE,
4831     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4832   },
4833   {
4834     Ybug_sB,                            FALSE,  TRUE,
4835     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4836   },
4837   {
4838     Ybug_w,                             FALSE,  FALSE,
4839     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4840   },
4841   {
4842     Ybug_wB,                            FALSE,  TRUE,
4843     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4844   },
4845   {
4846     Ybug_w_n,                           FALSE,  FALSE,
4847     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4848   },
4849   {
4850     Ybug_n_e,                           FALSE,  FALSE,
4851     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4852   },
4853   {
4854     Ybug_e_s,                           FALSE,  FALSE,
4855     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4856   },
4857   {
4858     Ybug_s_w,                           FALSE,  FALSE,
4859     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4860   },
4861   {
4862     Ybug_e_n,                           FALSE,  FALSE,
4863     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4864   },
4865   {
4866     Ybug_s_e,                           FALSE,  FALSE,
4867     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4868   },
4869   {
4870     Ybug_w_s,                           FALSE,  FALSE,
4871     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4872   },
4873   {
4874     Ybug_n_w,                           FALSE,  FALSE,
4875     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4876   },
4877   {
4878     Ybug_stone,                         FALSE,  FALSE,
4879     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
4880   },
4881   {
4882     Ybug_spring,                        FALSE,  FALSE,
4883     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
4884   },
4885   {
4886     Xtank_n,                            TRUE,   FALSE,
4887     EL_SPACESHIP_UP,                    -1, -1
4888   },
4889   {
4890     Xtank_e,                            TRUE,   FALSE,
4891     EL_SPACESHIP_RIGHT,                 -1, -1
4892   },
4893   {
4894     Xtank_s,                            TRUE,   FALSE,
4895     EL_SPACESHIP_DOWN,                  -1, -1
4896   },
4897   {
4898     Xtank_w,                            TRUE,   FALSE,
4899     EL_SPACESHIP_LEFT,                  -1, -1
4900   },
4901   {
4902     Xtank_gon,                          FALSE,  FALSE,
4903     EL_SPACESHIP_UP,                    -1, -1
4904   },
4905   {
4906     Xtank_goe,                          FALSE,  FALSE,
4907     EL_SPACESHIP_RIGHT,                 -1, -1
4908   },
4909   {
4910     Xtank_gos,                          FALSE,  FALSE,
4911     EL_SPACESHIP_DOWN,                  -1, -1
4912   },
4913   {
4914     Xtank_gow,                          FALSE,  FALSE,
4915     EL_SPACESHIP_LEFT,                  -1, -1
4916   },
4917   {
4918     Ytank_n,                            FALSE,  FALSE,
4919     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4920   },
4921   {
4922     Ytank_nB,                           FALSE,  TRUE,
4923     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4924   },
4925   {
4926     Ytank_e,                            FALSE,  FALSE,
4927     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4928   },
4929   {
4930     Ytank_eB,                           FALSE,  TRUE,
4931     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4932   },
4933   {
4934     Ytank_s,                            FALSE,  FALSE,
4935     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4936   },
4937   {
4938     Ytank_sB,                           FALSE,  TRUE,
4939     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4940   },
4941   {
4942     Ytank_w,                            FALSE,  FALSE,
4943     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4944   },
4945   {
4946     Ytank_wB,                           FALSE,  TRUE,
4947     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4948   },
4949   {
4950     Ytank_w_n,                          FALSE,  FALSE,
4951     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4952   },
4953   {
4954     Ytank_n_e,                          FALSE,  FALSE,
4955     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4956   },
4957   {
4958     Ytank_e_s,                          FALSE,  FALSE,
4959     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4960   },
4961   {
4962     Ytank_s_w,                          FALSE,  FALSE,
4963     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4964   },
4965   {
4966     Ytank_e_n,                          FALSE,  FALSE,
4967     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4968   },
4969   {
4970     Ytank_s_e,                          FALSE,  FALSE,
4971     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4972   },
4973   {
4974     Ytank_w_s,                          FALSE,  FALSE,
4975     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4976   },
4977   {
4978     Ytank_n_w,                          FALSE,  FALSE,
4979     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4980   },
4981   {
4982     Ytank_stone,                        FALSE,  FALSE,
4983     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
4984   },
4985   {
4986     Ytank_spring,                       FALSE,  FALSE,
4987     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
4988   },
4989   {
4990     Xandroid,                           TRUE,   FALSE,
4991     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
4992   },
4993   {
4994     Xandroid_1_n,                       FALSE,  FALSE,
4995     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4996   },
4997   {
4998     Xandroid_2_n,                       FALSE,  FALSE,
4999     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
5000   },
5001   {
5002     Xandroid_1_e,                       FALSE,  FALSE,
5003     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5004   },
5005   {
5006     Xandroid_2_e,                       FALSE,  FALSE,
5007     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5008   },
5009   {
5010     Xandroid_1_w,                       FALSE,  FALSE,
5011     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5012   },
5013   {
5014     Xandroid_2_w,                       FALSE,  FALSE,
5015     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5016   },
5017   {
5018     Xandroid_1_s,                       FALSE,  FALSE,
5019     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5020   },
5021   {
5022     Xandroid_2_s,                       FALSE,  FALSE,
5023     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5024   },
5025   {
5026     Yandroid_n,                         FALSE,  FALSE,
5027     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5028   },
5029   {
5030     Yandroid_nB,                        FALSE,  TRUE,
5031     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5032   },
5033   {
5034     Yandroid_ne,                        FALSE,  FALSE,
5035     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
5036   },
5037   {
5038     Yandroid_neB,                       FALSE,  TRUE,
5039     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
5040   },
5041   {
5042     Yandroid_e,                         FALSE,  FALSE,
5043     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5044   },
5045   {
5046     Yandroid_eB,                        FALSE,  TRUE,
5047     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5048   },
5049   {
5050     Yandroid_se,                        FALSE,  FALSE,
5051     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
5052   },
5053   {
5054     Yandroid_seB,                       FALSE,  TRUE,
5055     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5056   },
5057   {
5058     Yandroid_s,                         FALSE,  FALSE,
5059     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5060   },
5061   {
5062     Yandroid_sB,                        FALSE,  TRUE,
5063     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5064   },
5065   {
5066     Yandroid_sw,                        FALSE,  FALSE,
5067     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
5068   },
5069   {
5070     Yandroid_swB,                       FALSE,  TRUE,
5071     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
5072   },
5073   {
5074     Yandroid_w,                         FALSE,  FALSE,
5075     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5076   },
5077   {
5078     Yandroid_wB,                        FALSE,  TRUE,
5079     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5080   },
5081   {
5082     Yandroid_nw,                        FALSE,  FALSE,
5083     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
5084   },
5085   {
5086     Yandroid_nwB,                       FALSE,  TRUE,
5087     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
5088   },
5089   {
5090     Xspring,                            TRUE,   FALSE,
5091     EL_SPRING,                          -1, -1
5092   },
5093   {
5094     Xspring_pause,                      FALSE,  FALSE,
5095     EL_SPRING,                          -1, -1
5096   },
5097   {
5098     Xspring_e,                          FALSE,  FALSE,
5099     EL_SPRING,                          -1, -1
5100   },
5101   {
5102     Xspring_w,                          FALSE,  FALSE,
5103     EL_SPRING,                          -1, -1
5104   },
5105   {
5106     Xspring_fall,                       FALSE,  FALSE,
5107     EL_SPRING,                          -1, -1
5108   },
5109   {
5110     Yspring_s,                          FALSE,  FALSE,
5111     EL_SPRING,                          ACTION_FALLING, -1
5112   },
5113   {
5114     Yspring_sB,                         FALSE,  TRUE,
5115     EL_SPRING,                          ACTION_FALLING, -1
5116   },
5117   {
5118     Yspring_e,                          FALSE,  FALSE,
5119     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5120   },
5121   {
5122     Yspring_eB,                         FALSE,  TRUE,
5123     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5124   },
5125   {
5126     Yspring_w,                          FALSE,  FALSE,
5127     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5128   },
5129   {
5130     Yspring_wB,                         FALSE,  TRUE,
5131     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5132   },
5133   {
5134     Yspring_kill_e,                     FALSE,  FALSE,
5135     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5136   },
5137   {
5138     Yspring_kill_eB,                    FALSE,  TRUE,
5139     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5140   },
5141   {
5142     Yspring_kill_w,                     FALSE,  FALSE,
5143     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5144   },
5145   {
5146     Yspring_kill_wB,                    FALSE,  TRUE,
5147     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5148   },
5149   {
5150     Xeater_n,                           TRUE,   FALSE,
5151     EL_YAMYAM_UP,                       -1, -1
5152   },
5153   {
5154     Xeater_e,                           TRUE,   FALSE,
5155     EL_YAMYAM_RIGHT,                    -1, -1
5156   },
5157   {
5158     Xeater_w,                           TRUE,   FALSE,
5159     EL_YAMYAM_LEFT,                     -1, -1
5160   },
5161   {
5162     Xeater_s,                           TRUE,   FALSE,
5163     EL_YAMYAM_DOWN,                     -1, -1
5164   },
5165   {
5166     Yeater_n,                           FALSE,  FALSE,
5167     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5168   },
5169   {
5170     Yeater_nB,                          FALSE,  TRUE,
5171     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5172   },
5173   {
5174     Yeater_e,                           FALSE,  FALSE,
5175     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5176   },
5177   {
5178     Yeater_eB,                          FALSE,  TRUE,
5179     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5180   },
5181   {
5182     Yeater_s,                           FALSE,  FALSE,
5183     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5184   },
5185   {
5186     Yeater_sB,                          FALSE,  TRUE,
5187     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5188   },
5189   {
5190     Yeater_w,                           FALSE,  FALSE,
5191     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5192   },
5193   {
5194     Yeater_wB,                          FALSE,  TRUE,
5195     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5196   },
5197   {
5198     Yeater_stone,                       FALSE,  FALSE,
5199     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
5200   },
5201   {
5202     Yeater_spring,                      FALSE,  FALSE,
5203     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
5204   },
5205   {
5206     Xalien,                             TRUE,   FALSE,
5207     EL_ROBOT,                           -1, -1
5208   },
5209   {
5210     Xalien_pause,                       FALSE,  FALSE,
5211     EL_ROBOT,                           -1, -1
5212   },
5213   {
5214     Yalien_n,                           FALSE,  FALSE,
5215     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5216   },
5217   {
5218     Yalien_nB,                          FALSE,  TRUE,
5219     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5220   },
5221   {
5222     Yalien_e,                           FALSE,  FALSE,
5223     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5224   },
5225   {
5226     Yalien_eB,                          FALSE,  TRUE,
5227     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5228   },
5229   {
5230     Yalien_s,                           FALSE,  FALSE,
5231     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5232   },
5233   {
5234     Yalien_sB,                          FALSE,  TRUE,
5235     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5236   },
5237   {
5238     Yalien_w,                           FALSE,  FALSE,
5239     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5240   },
5241   {
5242     Yalien_wB,                          FALSE,  TRUE,
5243     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5244   },
5245   {
5246     Yalien_stone,                       FALSE,  FALSE,
5247     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
5248   },
5249   {
5250     Yalien_spring,                      FALSE,  FALSE,
5251     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
5252   },
5253   {
5254     Xemerald,                           TRUE,   FALSE,
5255     EL_EMERALD,                         -1, -1
5256   },
5257   {
5258     Xemerald_pause,                     FALSE,  FALSE,
5259     EL_EMERALD,                         -1, -1
5260   },
5261   {
5262     Xemerald_fall,                      FALSE,  FALSE,
5263     EL_EMERALD,                         -1, -1
5264   },
5265   {
5266     Xemerald_shine,                     FALSE,  FALSE,
5267     EL_EMERALD,                         ACTION_TWINKLING, -1
5268   },
5269   {
5270     Yemerald_s,                         FALSE,  FALSE,
5271     EL_EMERALD,                         ACTION_FALLING, -1
5272   },
5273   {
5274     Yemerald_sB,                        FALSE,  TRUE,
5275     EL_EMERALD,                         ACTION_FALLING, -1
5276   },
5277   {
5278     Yemerald_e,                         FALSE,  FALSE,
5279     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5280   },
5281   {
5282     Yemerald_eB,                        FALSE,  TRUE,
5283     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5284   },
5285   {
5286     Yemerald_w,                         FALSE,  FALSE,
5287     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5288   },
5289   {
5290     Yemerald_wB,                        FALSE,  TRUE,
5291     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5292   },
5293   {
5294     Yemerald_eat,                       FALSE,  FALSE,
5295     EL_EMERALD,                         ACTION_COLLECTING, -1
5296   },
5297   {
5298     Yemerald_stone,                     FALSE,  FALSE,
5299     EL_NUT,                             ACTION_BREAKING, -1
5300   },
5301   {
5302     Xdiamond,                           TRUE,   FALSE,
5303     EL_DIAMOND,                         -1, -1
5304   },
5305   {
5306     Xdiamond_pause,                     FALSE,  FALSE,
5307     EL_DIAMOND,                         -1, -1
5308   },
5309   {
5310     Xdiamond_fall,                      FALSE,  FALSE,
5311     EL_DIAMOND,                         -1, -1
5312   },
5313   {
5314     Xdiamond_shine,                     FALSE,  FALSE,
5315     EL_DIAMOND,                         ACTION_TWINKLING, -1
5316   },
5317   {
5318     Ydiamond_s,                         FALSE,  FALSE,
5319     EL_DIAMOND,                         ACTION_FALLING, -1
5320   },
5321   {
5322     Ydiamond_sB,                        FALSE,  TRUE,
5323     EL_DIAMOND,                         ACTION_FALLING, -1
5324   },
5325   {
5326     Ydiamond_e,                         FALSE,  FALSE,
5327     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5328   },
5329   {
5330     Ydiamond_eB,                        FALSE,  TRUE,
5331     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5332   },
5333   {
5334     Ydiamond_w,                         FALSE,  FALSE,
5335     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5336   },
5337   {
5338     Ydiamond_wB,                        FALSE,  TRUE,
5339     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5340   },
5341   {
5342     Ydiamond_eat,                       FALSE,  FALSE,
5343     EL_DIAMOND,                         ACTION_COLLECTING, -1
5344   },
5345   {
5346     Ydiamond_stone,                     FALSE,  FALSE,
5347     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
5348   },
5349   {
5350     Xdrip_fall,                         TRUE,   FALSE,
5351     EL_AMOEBA_DROP,                     -1, -1
5352   },
5353   {
5354     Xdrip_stretch,                      FALSE,  FALSE,
5355     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5356   },
5357   {
5358     Xdrip_stretchB,                     FALSE,  TRUE,
5359     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5360   },
5361   {
5362     Xdrip_eat,                          FALSE,  FALSE,
5363     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
5364   },
5365   {
5366     Ydrip_s1,                           FALSE,  FALSE,
5367     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5368   },
5369   {
5370     Ydrip_s1B,                          FALSE,  TRUE,
5371     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5372   },
5373   {
5374     Ydrip_s2,                           FALSE,  FALSE,
5375     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5376   },
5377   {
5378     Ydrip_s2B,                          FALSE,  TRUE,
5379     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5380   },
5381   {
5382     Xbomb,                              TRUE,   FALSE,
5383     EL_BOMB,                            -1, -1
5384   },
5385   {
5386     Xbomb_pause,                        FALSE,  FALSE,
5387     EL_BOMB,                            -1, -1
5388   },
5389   {
5390     Xbomb_fall,                         FALSE,  FALSE,
5391     EL_BOMB,                            -1, -1
5392   },
5393   {
5394     Ybomb_s,                            FALSE,  FALSE,
5395     EL_BOMB,                            ACTION_FALLING, -1
5396   },
5397   {
5398     Ybomb_sB,                           FALSE,  TRUE,
5399     EL_BOMB,                            ACTION_FALLING, -1
5400   },
5401   {
5402     Ybomb_e,                            FALSE,  FALSE,
5403     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5404   },
5405   {
5406     Ybomb_eB,                           FALSE,  TRUE,
5407     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5408   },
5409   {
5410     Ybomb_w,                            FALSE,  FALSE,
5411     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5412   },
5413   {
5414     Ybomb_wB,                           FALSE,  TRUE,
5415     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5416   },
5417   {
5418     Ybomb_eat,                          FALSE,  FALSE,
5419     EL_BOMB,                            ACTION_ACTIVATING, -1
5420   },
5421   {
5422     Xballoon,                           TRUE,   FALSE,
5423     EL_BALLOON,                         -1, -1
5424   },
5425   {
5426     Yballoon_n,                         FALSE,  FALSE,
5427     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5428   },
5429   {
5430     Yballoon_nB,                        FALSE,  TRUE,
5431     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5432   },
5433   {
5434     Yballoon_e,                         FALSE,  FALSE,
5435     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5436   },
5437   {
5438     Yballoon_eB,                        FALSE,  TRUE,
5439     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5440   },
5441   {
5442     Yballoon_s,                         FALSE,  FALSE,
5443     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5444   },
5445   {
5446     Yballoon_sB,                        FALSE,  TRUE,
5447     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5448   },
5449   {
5450     Yballoon_w,                         FALSE,  FALSE,
5451     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5452   },
5453   {
5454     Yballoon_wB,                        FALSE,  TRUE,
5455     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5456   },
5457   {
5458     Xgrass,                             TRUE,   FALSE,
5459     EL_EMC_GRASS,                       -1, -1
5460   },
5461   {
5462     Ygrass_nB,                          FALSE,  FALSE,
5463     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
5464   },
5465   {
5466     Ygrass_eB,                          FALSE,  FALSE,
5467     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
5468   },
5469   {
5470     Ygrass_sB,                          FALSE,  FALSE,
5471     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
5472   },
5473   {
5474     Ygrass_wB,                          FALSE,  FALSE,
5475     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
5476   },
5477   {
5478     Xdirt,                              TRUE,   FALSE,
5479     EL_SAND,                            -1, -1
5480   },
5481   {
5482     Ydirt_nB,                           FALSE,  FALSE,
5483     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
5484   },
5485   {
5486     Ydirt_eB,                           FALSE,  FALSE,
5487     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
5488   },
5489   {
5490     Ydirt_sB,                           FALSE,  FALSE,
5491     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
5492   },
5493   {
5494     Ydirt_wB,                           FALSE,  FALSE,
5495     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
5496   },
5497   {
5498     Xacid_ne,                           TRUE,   FALSE,
5499     EL_ACID_POOL_TOPRIGHT,              -1, -1
5500   },
5501   {
5502     Xacid_se,                           TRUE,   FALSE,
5503     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
5504   },
5505   {
5506     Xacid_s,                            TRUE,   FALSE,
5507     EL_ACID_POOL_BOTTOM,                -1, -1
5508   },
5509   {
5510     Xacid_sw,                           TRUE,   FALSE,
5511     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
5512   },
5513   {
5514     Xacid_nw,                           TRUE,   FALSE,
5515     EL_ACID_POOL_TOPLEFT,               -1, -1
5516   },
5517   {
5518     Xacid_1,                            TRUE,   FALSE,
5519     EL_ACID,                            -1, -1
5520   },
5521   {
5522     Xacid_2,                            FALSE,  FALSE,
5523     EL_ACID,                            -1, -1
5524   },
5525   {
5526     Xacid_3,                            FALSE,  FALSE,
5527     EL_ACID,                            -1, -1
5528   },
5529   {
5530     Xacid_4,                            FALSE,  FALSE,
5531     EL_ACID,                            -1, -1
5532   },
5533   {
5534     Xacid_5,                            FALSE,  FALSE,
5535     EL_ACID,                            -1, -1
5536   },
5537   {
5538     Xacid_6,                            FALSE,  FALSE,
5539     EL_ACID,                            -1, -1
5540   },
5541   {
5542     Xacid_7,                            FALSE,  FALSE,
5543     EL_ACID,                            -1, -1
5544   },
5545   {
5546     Xacid_8,                            FALSE,  FALSE,
5547     EL_ACID,                            -1, -1
5548   },
5549   {
5550     Xball_1,                            TRUE,   FALSE,
5551     EL_EMC_MAGIC_BALL,                  -1, -1
5552   },
5553   {
5554     Xball_1B,                           FALSE,  FALSE,
5555     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5556   },
5557   {
5558     Xball_2,                            FALSE,  FALSE,
5559     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5560   },
5561   {
5562     Xball_2B,                           FALSE,  FALSE,
5563     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5564   },
5565   {
5566     Yball_eat,                          FALSE,  FALSE,
5567     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
5568   },
5569   {
5570     Ykey_1_eat,                         FALSE,  FALSE,
5571     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
5572   },
5573   {
5574     Ykey_2_eat,                         FALSE,  FALSE,
5575     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
5576   },
5577   {
5578     Ykey_3_eat,                         FALSE,  FALSE,
5579     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
5580   },
5581   {
5582     Ykey_4_eat,                         FALSE,  FALSE,
5583     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
5584   },
5585   {
5586     Ykey_5_eat,                         FALSE,  FALSE,
5587     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
5588   },
5589   {
5590     Ykey_6_eat,                         FALSE,  FALSE,
5591     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
5592   },
5593   {
5594     Ykey_7_eat,                         FALSE,  FALSE,
5595     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
5596   },
5597   {
5598     Ykey_8_eat,                         FALSE,  FALSE,
5599     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
5600   },
5601   {
5602     Ylenses_eat,                        FALSE,  FALSE,
5603     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
5604   },
5605   {
5606     Ymagnify_eat,                       FALSE,  FALSE,
5607     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
5608   },
5609   {
5610     Ygrass_eat,                         FALSE,  FALSE,
5611     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
5612   },
5613   {
5614     Ydirt_eat,                          FALSE,  FALSE,
5615     EL_SAND,                            ACTION_SNAPPING, -1
5616   },
5617   {
5618     Xgrow_ns,                           TRUE,   FALSE,
5619     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
5620   },
5621   {
5622     Ygrow_ns_eat,                       FALSE,  FALSE,
5623     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
5624   },
5625   {
5626     Xgrow_ew,                           TRUE,   FALSE,
5627     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
5628   },
5629   {
5630     Ygrow_ew_eat,                       FALSE,  FALSE,
5631     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
5632   },
5633   {
5634     Xwonderwall,                        TRUE,   FALSE,
5635     EL_MAGIC_WALL,                      -1, -1
5636   },
5637   {
5638     XwonderwallB,                       FALSE,  FALSE,
5639     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
5640   },
5641   {
5642     Xamoeba_1,                          TRUE,   FALSE,
5643     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5644   },
5645   {
5646     Xamoeba_2,                          FALSE,  FALSE,
5647     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5648   },
5649   {
5650     Xamoeba_3,                          FALSE,  FALSE,
5651     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5652   },
5653   {
5654     Xamoeba_4,                          FALSE,  FALSE,
5655     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5656   },
5657   {
5658     Xamoeba_5,                          TRUE,   FALSE,
5659     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5660   },
5661   {
5662     Xamoeba_6,                          FALSE,  FALSE,
5663     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5664   },
5665   {
5666     Xamoeba_7,                          FALSE,  FALSE,
5667     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5668   },
5669   {
5670     Xamoeba_8,                          FALSE,  FALSE,
5671     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5672   },
5673   {
5674     Xdoor_1,                            TRUE,   FALSE,
5675     EL_EM_GATE_1,                       -1, -1
5676   },
5677   {
5678     Xdoor_2,                            TRUE,   FALSE,
5679     EL_EM_GATE_2,                       -1, -1
5680   },
5681   {
5682     Xdoor_3,                            TRUE,   FALSE,
5683     EL_EM_GATE_3,                       -1, -1
5684   },
5685   {
5686     Xdoor_4,                            TRUE,   FALSE,
5687     EL_EM_GATE_4,                       -1, -1
5688   },
5689   {
5690     Xdoor_5,                            TRUE,   FALSE,
5691     EL_EMC_GATE_5,                      -1, -1
5692   },
5693   {
5694     Xdoor_6,                            TRUE,   FALSE,
5695     EL_EMC_GATE_6,                      -1, -1
5696   },
5697   {
5698     Xdoor_7,                            TRUE,   FALSE,
5699     EL_EMC_GATE_7,                      -1, -1
5700   },
5701   {
5702     Xdoor_8,                            TRUE,   FALSE,
5703     EL_EMC_GATE_8,                      -1, -1
5704   },
5705   {
5706     Xkey_1,                             TRUE,   FALSE,
5707     EL_EM_KEY_1,                        -1, -1
5708   },
5709   {
5710     Xkey_2,                             TRUE,   FALSE,
5711     EL_EM_KEY_2,                        -1, -1
5712   },
5713   {
5714     Xkey_3,                             TRUE,   FALSE,
5715     EL_EM_KEY_3,                        -1, -1
5716   },
5717   {
5718     Xkey_4,                             TRUE,   FALSE,
5719     EL_EM_KEY_4,                        -1, -1
5720   },
5721   {
5722     Xkey_5,                             TRUE,   FALSE,
5723     EL_EMC_KEY_5,                       -1, -1
5724   },
5725   {
5726     Xkey_6,                             TRUE,   FALSE,
5727     EL_EMC_KEY_6,                       -1, -1
5728   },
5729   {
5730     Xkey_7,                             TRUE,   FALSE,
5731     EL_EMC_KEY_7,                       -1, -1
5732   },
5733   {
5734     Xkey_8,                             TRUE,   FALSE,
5735     EL_EMC_KEY_8,                       -1, -1
5736   },
5737   {
5738     Xwind_n,                            TRUE,   FALSE,
5739     EL_BALLOON_SWITCH_UP,               -1, -1
5740   },
5741   {
5742     Xwind_e,                            TRUE,   FALSE,
5743     EL_BALLOON_SWITCH_RIGHT,            -1, -1
5744   },
5745   {
5746     Xwind_s,                            TRUE,   FALSE,
5747     EL_BALLOON_SWITCH_DOWN,             -1, -1
5748   },
5749   {
5750     Xwind_w,                            TRUE,   FALSE,
5751     EL_BALLOON_SWITCH_LEFT,             -1, -1
5752   },
5753   {
5754     Xwind_nesw,                         TRUE,   FALSE,
5755     EL_BALLOON_SWITCH_ANY,              -1, -1
5756   },
5757   {
5758     Xwind_stop,                         TRUE,   FALSE,
5759     EL_BALLOON_SWITCH_NONE,             -1, -1
5760   },
5761   {
5762     Xexit,                              TRUE,   FALSE,
5763     EL_EM_EXIT_CLOSED,                  -1, -1
5764   },
5765   {
5766     Xexit_1,                            TRUE,   FALSE,
5767     EL_EM_EXIT_OPEN,                    -1, -1
5768   },
5769   {
5770     Xexit_2,                            FALSE,  FALSE,
5771     EL_EM_EXIT_OPEN,                    -1, -1
5772   },
5773   {
5774     Xexit_3,                            FALSE,  FALSE,
5775     EL_EM_EXIT_OPEN,                    -1, -1
5776   },
5777   {
5778     Xdynamite,                          TRUE,   FALSE,
5779     EL_EM_DYNAMITE,                     -1, -1
5780   },
5781   {
5782     Ydynamite_eat,                      FALSE,  FALSE,
5783     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
5784   },
5785   {
5786     Xdynamite_1,                        TRUE,   FALSE,
5787     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5788   },
5789   {
5790     Xdynamite_2,                        FALSE,  FALSE,
5791     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5792   },
5793   {
5794     Xdynamite_3,                        FALSE,  FALSE,
5795     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5796   },
5797   {
5798     Xdynamite_4,                        FALSE,  FALSE,
5799     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5800   },
5801   {
5802     Xbumper,                            TRUE,   FALSE,
5803     EL_EMC_SPRING_BUMPER,               -1, -1
5804   },
5805   {
5806     XbumperB,                           FALSE,  FALSE,
5807     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
5808   },
5809   {
5810     Xwheel,                             TRUE,   FALSE,
5811     EL_ROBOT_WHEEL,                     -1, -1
5812   },
5813   {
5814     XwheelB,                            FALSE,  FALSE,
5815     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
5816   },
5817   {
5818     Xswitch,                            TRUE,   FALSE,
5819     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
5820   },
5821   {
5822     XswitchB,                           FALSE,  FALSE,
5823     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
5824   },
5825   {
5826     Xsand,                              TRUE,   FALSE,
5827     EL_QUICKSAND_EMPTY,                 -1, -1
5828   },
5829   {
5830     Xsand_stone,                        TRUE,   FALSE,
5831     EL_QUICKSAND_FULL,                  -1, -1
5832   },
5833   {
5834     Xsand_stonein_1,                    FALSE,  TRUE,
5835     EL_ROCK,                            ACTION_FILLING, -1
5836   },
5837   {
5838     Xsand_stonein_2,                    FALSE,  TRUE,
5839     EL_ROCK,                            ACTION_FILLING, -1
5840   },
5841   {
5842     Xsand_stonein_3,                    FALSE,  TRUE,
5843     EL_ROCK,                            ACTION_FILLING, -1
5844   },
5845   {
5846     Xsand_stonein_4,                    FALSE,  TRUE,
5847     EL_ROCK,                            ACTION_FILLING, -1
5848   },
5849 #if 1
5850   {
5851     Xsand_stonesand_1,                  FALSE,  FALSE,
5852     EL_QUICKSAND_EMPTYING,              -1, -1
5853   },
5854   {
5855     Xsand_stonesand_2,                  FALSE,  FALSE,
5856     EL_QUICKSAND_EMPTYING,              -1, -1
5857   },
5858   {
5859     Xsand_stonesand_3,                  FALSE,  FALSE,
5860     EL_QUICKSAND_EMPTYING,              -1, -1
5861   },
5862   {
5863     Xsand_stonesand_4,                  FALSE,  FALSE,
5864     EL_QUICKSAND_EMPTYING,              -1, -1
5865   },
5866   {
5867     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
5868     EL_QUICKSAND_EMPTYING,              -1, -1
5869   },
5870   {
5871     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
5872     EL_QUICKSAND_EMPTYING,              -1, -1
5873   },
5874 #else
5875   {
5876     Xsand_stonesand_1,                  FALSE,  FALSE,
5877     EL_QUICKSAND_FULL,                  -1, -1
5878   },
5879   {
5880     Xsand_stonesand_2,                  FALSE,  FALSE,
5881     EL_QUICKSAND_FULL,                  -1, -1
5882   },
5883   {
5884     Xsand_stonesand_3,                  FALSE,  FALSE,
5885     EL_QUICKSAND_FULL,                  -1, -1
5886   },
5887   {
5888     Xsand_stonesand_4,                  FALSE,  FALSE,
5889     EL_QUICKSAND_FULL,                  -1, -1
5890   },
5891 #endif
5892   {
5893     Xsand_stoneout_1,                   FALSE,  FALSE,
5894     EL_ROCK,                            ACTION_EMPTYING, -1
5895   },
5896   {
5897     Xsand_stoneout_2,                   FALSE,  FALSE,
5898     EL_ROCK,                            ACTION_EMPTYING, -1
5899   },
5900 #if 1
5901   {
5902     Xsand_sandstone_1,                  FALSE,  FALSE,
5903     EL_QUICKSAND_FILLING,               -1, -1
5904   },
5905   {
5906     Xsand_sandstone_2,                  FALSE,  FALSE,
5907     EL_QUICKSAND_FILLING,               -1, -1
5908   },
5909   {
5910     Xsand_sandstone_3,                  FALSE,  FALSE,
5911     EL_QUICKSAND_FILLING,               -1, -1
5912   },
5913   {
5914     Xsand_sandstone_4,                  FALSE,  FALSE,
5915     EL_QUICKSAND_FILLING,               -1, -1
5916   },
5917 #else
5918   {
5919     Xsand_sandstone_1,                  FALSE,  FALSE,
5920     EL_QUICKSAND_FULL,                  -1, -1
5921   },
5922   {
5923     Xsand_sandstone_2,                  FALSE,  FALSE,
5924     EL_QUICKSAND_FULL,                  -1, -1
5925   },
5926   {
5927     Xsand_sandstone_3,                  FALSE,  FALSE,
5928     EL_QUICKSAND_FULL,                  -1, -1
5929   },
5930   {
5931     Xsand_sandstone_4,                  FALSE,  FALSE,
5932     EL_QUICKSAND_FULL,                  -1, -1
5933   },
5934 #endif
5935   {
5936     Xplant,                             TRUE,   FALSE,
5937     EL_EMC_PLANT,                       -1, -1
5938   },
5939   {
5940     Yplant,                             FALSE,  FALSE,
5941     EL_EMC_PLANT,                       -1, -1
5942   },
5943   {
5944     Xlenses,                            TRUE,   FALSE,
5945     EL_EMC_LENSES,                      -1, -1
5946   },
5947   {
5948     Xmagnify,                           TRUE,   FALSE,
5949     EL_EMC_MAGNIFIER,                   -1, -1
5950   },
5951   {
5952     Xdripper,                           TRUE,   FALSE,
5953     EL_EMC_DRIPPER,                     -1, -1
5954   },
5955   {
5956     XdripperB,                          FALSE,  FALSE,
5957     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
5958   },
5959   {
5960     Xfake_blank,                        TRUE,   FALSE,
5961     EL_INVISIBLE_WALL,                  -1, -1
5962   },
5963   {
5964     Xfake_blankB,                       FALSE,  FALSE,
5965     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
5966   },
5967   {
5968     Xfake_grass,                        TRUE,   FALSE,
5969     EL_EMC_FAKE_GRASS,                  -1, -1
5970   },
5971   {
5972     Xfake_grassB,                       FALSE,  FALSE,
5973     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
5974   },
5975   {
5976     Xfake_door_1,                       TRUE,   FALSE,
5977     EL_EM_GATE_1_GRAY,                  -1, -1
5978   },
5979   {
5980     Xfake_door_2,                       TRUE,   FALSE,
5981     EL_EM_GATE_2_GRAY,                  -1, -1
5982   },
5983   {
5984     Xfake_door_3,                       TRUE,   FALSE,
5985     EL_EM_GATE_3_GRAY,                  -1, -1
5986   },
5987   {
5988     Xfake_door_4,                       TRUE,   FALSE,
5989     EL_EM_GATE_4_GRAY,                  -1, -1
5990   },
5991   {
5992     Xfake_door_5,                       TRUE,   FALSE,
5993     EL_EMC_GATE_5_GRAY,                 -1, -1
5994   },
5995   {
5996     Xfake_door_6,                       TRUE,   FALSE,
5997     EL_EMC_GATE_6_GRAY,                 -1, -1
5998   },
5999   {
6000     Xfake_door_7,                       TRUE,   FALSE,
6001     EL_EMC_GATE_7_GRAY,                 -1, -1
6002   },
6003   {
6004     Xfake_door_8,                       TRUE,   FALSE,
6005     EL_EMC_GATE_8_GRAY,                 -1, -1
6006   },
6007   {
6008     Xfake_acid_1,                       TRUE,   FALSE,
6009     EL_EMC_FAKE_ACID,                   -1, -1
6010   },
6011   {
6012     Xfake_acid_2,                       FALSE,  FALSE,
6013     EL_EMC_FAKE_ACID,                   -1, -1
6014   },
6015   {
6016     Xfake_acid_3,                       FALSE,  FALSE,
6017     EL_EMC_FAKE_ACID,                   -1, -1
6018   },
6019   {
6020     Xfake_acid_4,                       FALSE,  FALSE,
6021     EL_EMC_FAKE_ACID,                   -1, -1
6022   },
6023   {
6024     Xfake_acid_5,                       FALSE,  FALSE,
6025     EL_EMC_FAKE_ACID,                   -1, -1
6026   },
6027   {
6028     Xfake_acid_6,                       FALSE,  FALSE,
6029     EL_EMC_FAKE_ACID,                   -1, -1
6030   },
6031   {
6032     Xfake_acid_7,                       FALSE,  FALSE,
6033     EL_EMC_FAKE_ACID,                   -1, -1
6034   },
6035   {
6036     Xfake_acid_8,                       FALSE,  FALSE,
6037     EL_EMC_FAKE_ACID,                   -1, -1
6038   },
6039   {
6040     Xsteel_1,                           TRUE,   FALSE,
6041     EL_STEELWALL,                       -1, -1
6042   },
6043   {
6044     Xsteel_2,                           TRUE,   FALSE,
6045     EL_EMC_STEELWALL_2,                 -1, -1
6046   },
6047   {
6048     Xsteel_3,                           TRUE,   FALSE,
6049     EL_EMC_STEELWALL_3,                 -1, -1
6050   },
6051   {
6052     Xsteel_4,                           TRUE,   FALSE,
6053     EL_EMC_STEELWALL_4,                 -1, -1
6054   },
6055   {
6056     Xwall_1,                            TRUE,   FALSE,
6057     EL_WALL,                            -1, -1
6058   },
6059   {
6060     Xwall_2,                            TRUE,   FALSE,
6061     EL_EMC_WALL_14,                     -1, -1
6062   },
6063   {
6064     Xwall_3,                            TRUE,   FALSE,
6065     EL_EMC_WALL_15,                     -1, -1
6066   },
6067   {
6068     Xwall_4,                            TRUE,   FALSE,
6069     EL_EMC_WALL_16,                     -1, -1
6070   },
6071   {
6072     Xround_wall_1,                      TRUE,   FALSE,
6073     EL_WALL_SLIPPERY,                   -1, -1
6074   },
6075   {
6076     Xround_wall_2,                      TRUE,   FALSE,
6077     EL_EMC_WALL_SLIPPERY_2,             -1, -1
6078   },
6079   {
6080     Xround_wall_3,                      TRUE,   FALSE,
6081     EL_EMC_WALL_SLIPPERY_3,             -1, -1
6082   },
6083   {
6084     Xround_wall_4,                      TRUE,   FALSE,
6085     EL_EMC_WALL_SLIPPERY_4,             -1, -1
6086   },
6087   {
6088     Xdecor_1,                           TRUE,   FALSE,
6089     EL_EMC_WALL_8,                      -1, -1
6090   },
6091   {
6092     Xdecor_2,                           TRUE,   FALSE,
6093     EL_EMC_WALL_6,                      -1, -1
6094   },
6095   {
6096     Xdecor_3,                           TRUE,   FALSE,
6097     EL_EMC_WALL_4,                      -1, -1
6098   },
6099   {
6100     Xdecor_4,                           TRUE,   FALSE,
6101     EL_EMC_WALL_7,                      -1, -1
6102   },
6103   {
6104     Xdecor_5,                           TRUE,   FALSE,
6105     EL_EMC_WALL_5,                      -1, -1
6106   },
6107   {
6108     Xdecor_6,                           TRUE,   FALSE,
6109     EL_EMC_WALL_9,                      -1, -1
6110   },
6111   {
6112     Xdecor_7,                           TRUE,   FALSE,
6113     EL_EMC_WALL_10,                     -1, -1
6114   },
6115   {
6116     Xdecor_8,                           TRUE,   FALSE,
6117     EL_EMC_WALL_1,                      -1, -1
6118   },
6119   {
6120     Xdecor_9,                           TRUE,   FALSE,
6121     EL_EMC_WALL_2,                      -1, -1
6122   },
6123   {
6124     Xdecor_10,                          TRUE,   FALSE,
6125     EL_EMC_WALL_3,                      -1, -1
6126   },
6127   {
6128     Xdecor_11,                          TRUE,   FALSE,
6129     EL_EMC_WALL_11,                     -1, -1
6130   },
6131   {
6132     Xdecor_12,                          TRUE,   FALSE,
6133     EL_EMC_WALL_12,                     -1, -1
6134   },
6135   {
6136     Xalpha_0,                           TRUE,   FALSE,
6137     EL_CHAR('0'),                       -1, -1
6138   },
6139   {
6140     Xalpha_1,                           TRUE,   FALSE,
6141     EL_CHAR('1'),                       -1, -1
6142   },
6143   {
6144     Xalpha_2,                           TRUE,   FALSE,
6145     EL_CHAR('2'),                       -1, -1
6146   },
6147   {
6148     Xalpha_3,                           TRUE,   FALSE,
6149     EL_CHAR('3'),                       -1, -1
6150   },
6151   {
6152     Xalpha_4,                           TRUE,   FALSE,
6153     EL_CHAR('4'),                       -1, -1
6154   },
6155   {
6156     Xalpha_5,                           TRUE,   FALSE,
6157     EL_CHAR('5'),                       -1, -1
6158   },
6159   {
6160     Xalpha_6,                           TRUE,   FALSE,
6161     EL_CHAR('6'),                       -1, -1
6162   },
6163   {
6164     Xalpha_7,                           TRUE,   FALSE,
6165     EL_CHAR('7'),                       -1, -1
6166   },
6167   {
6168     Xalpha_8,                           TRUE,   FALSE,
6169     EL_CHAR('8'),                       -1, -1
6170   },
6171   {
6172     Xalpha_9,                           TRUE,   FALSE,
6173     EL_CHAR('9'),                       -1, -1
6174   },
6175   {
6176     Xalpha_excla,                       TRUE,   FALSE,
6177     EL_CHAR('!'),                       -1, -1
6178   },
6179   {
6180     Xalpha_quote,                       TRUE,   FALSE,
6181     EL_CHAR('"'),                       -1, -1
6182   },
6183   {
6184     Xalpha_comma,                       TRUE,   FALSE,
6185     EL_CHAR(','),                       -1, -1
6186   },
6187   {
6188     Xalpha_minus,                       TRUE,   FALSE,
6189     EL_CHAR('-'),                       -1, -1
6190   },
6191   {
6192     Xalpha_perio,                       TRUE,   FALSE,
6193     EL_CHAR('.'),                       -1, -1
6194   },
6195   {
6196     Xalpha_colon,                       TRUE,   FALSE,
6197     EL_CHAR(':'),                       -1, -1
6198   },
6199   {
6200     Xalpha_quest,                       TRUE,   FALSE,
6201     EL_CHAR('?'),                       -1, -1
6202   },
6203   {
6204     Xalpha_a,                           TRUE,   FALSE,
6205     EL_CHAR('A'),                       -1, -1
6206   },
6207   {
6208     Xalpha_b,                           TRUE,   FALSE,
6209     EL_CHAR('B'),                       -1, -1
6210   },
6211   {
6212     Xalpha_c,                           TRUE,   FALSE,
6213     EL_CHAR('C'),                       -1, -1
6214   },
6215   {
6216     Xalpha_d,                           TRUE,   FALSE,
6217     EL_CHAR('D'),                       -1, -1
6218   },
6219   {
6220     Xalpha_e,                           TRUE,   FALSE,
6221     EL_CHAR('E'),                       -1, -1
6222   },
6223   {
6224     Xalpha_f,                           TRUE,   FALSE,
6225     EL_CHAR('F'),                       -1, -1
6226   },
6227   {
6228     Xalpha_g,                           TRUE,   FALSE,
6229     EL_CHAR('G'),                       -1, -1
6230   },
6231   {
6232     Xalpha_h,                           TRUE,   FALSE,
6233     EL_CHAR('H'),                       -1, -1
6234   },
6235   {
6236     Xalpha_i,                           TRUE,   FALSE,
6237     EL_CHAR('I'),                       -1, -1
6238   },
6239   {
6240     Xalpha_j,                           TRUE,   FALSE,
6241     EL_CHAR('J'),                       -1, -1
6242   },
6243   {
6244     Xalpha_k,                           TRUE,   FALSE,
6245     EL_CHAR('K'),                       -1, -1
6246   },
6247   {
6248     Xalpha_l,                           TRUE,   FALSE,
6249     EL_CHAR('L'),                       -1, -1
6250   },
6251   {
6252     Xalpha_m,                           TRUE,   FALSE,
6253     EL_CHAR('M'),                       -1, -1
6254   },
6255   {
6256     Xalpha_n,                           TRUE,   FALSE,
6257     EL_CHAR('N'),                       -1, -1
6258   },
6259   {
6260     Xalpha_o,                           TRUE,   FALSE,
6261     EL_CHAR('O'),                       -1, -1
6262   },
6263   {
6264     Xalpha_p,                           TRUE,   FALSE,
6265     EL_CHAR('P'),                       -1, -1
6266   },
6267   {
6268     Xalpha_q,                           TRUE,   FALSE,
6269     EL_CHAR('Q'),                       -1, -1
6270   },
6271   {
6272     Xalpha_r,                           TRUE,   FALSE,
6273     EL_CHAR('R'),                       -1, -1
6274   },
6275   {
6276     Xalpha_s,                           TRUE,   FALSE,
6277     EL_CHAR('S'),                       -1, -1
6278   },
6279   {
6280     Xalpha_t,                           TRUE,   FALSE,
6281     EL_CHAR('T'),                       -1, -1
6282   },
6283   {
6284     Xalpha_u,                           TRUE,   FALSE,
6285     EL_CHAR('U'),                       -1, -1
6286   },
6287   {
6288     Xalpha_v,                           TRUE,   FALSE,
6289     EL_CHAR('V'),                       -1, -1
6290   },
6291   {
6292     Xalpha_w,                           TRUE,   FALSE,
6293     EL_CHAR('W'),                       -1, -1
6294   },
6295   {
6296     Xalpha_x,                           TRUE,   FALSE,
6297     EL_CHAR('X'),                       -1, -1
6298   },
6299   {
6300     Xalpha_y,                           TRUE,   FALSE,
6301     EL_CHAR('Y'),                       -1, -1
6302   },
6303   {
6304     Xalpha_z,                           TRUE,   FALSE,
6305     EL_CHAR('Z'),                       -1, -1
6306   },
6307   {
6308     Xalpha_arrow_e,                     TRUE,   FALSE,
6309     EL_CHAR('>'),                       -1, -1
6310   },
6311   {
6312     Xalpha_arrow_w,                     TRUE,   FALSE,
6313     EL_CHAR('<'),                       -1, -1
6314   },
6315   {
6316     Xalpha_copyr,                       TRUE,   FALSE,
6317     EL_CHAR('©'),                       -1, -1
6318   },
6319
6320   {
6321     Xboom_bug,                          FALSE,  FALSE,
6322     EL_BUG,                             ACTION_EXPLODING, -1
6323   },
6324   {
6325     Xboom_bomb,                         FALSE,  FALSE,
6326     EL_BOMB,                            ACTION_EXPLODING, -1
6327   },
6328   {
6329     Xboom_android,                      FALSE,  FALSE,
6330     EL_EMC_ANDROID,                     ACTION_OTHER, -1
6331   },
6332   {
6333     Xboom_1,                            FALSE,  FALSE,
6334     EL_DEFAULT,                         ACTION_EXPLODING, -1
6335   },
6336   {
6337     Xboom_2,                            FALSE,  FALSE,
6338     EL_DEFAULT,                         ACTION_EXPLODING, -1
6339   },
6340   {
6341     Znormal,                            FALSE,  FALSE,
6342     EL_EMPTY,                           -1, -1
6343   },
6344   {
6345     Zdynamite,                          FALSE,  FALSE,
6346     EL_EMPTY,                           -1, -1
6347   },
6348   {
6349     Zplayer,                            FALSE,  FALSE,
6350     EL_EMPTY,                           -1, -1
6351   },
6352   {
6353     ZBORDER,                            FALSE,  FALSE,
6354     EL_EMPTY,                           -1, -1
6355   },
6356
6357   {
6358     -1,                                 FALSE,  FALSE,
6359     -1,                                 -1, -1
6360   }
6361 };
6362
6363 static struct Mapping_EM_to_RND_player
6364 {
6365   int action_em;
6366   int player_nr;
6367
6368   int element_rnd;
6369   int action;
6370   int direction;
6371 }
6372 em_player_mapping_list[] =
6373 {
6374   {
6375     SPR_walk + 0,                       0,
6376     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
6377   },
6378   {
6379     SPR_walk + 1,                       0,
6380     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
6381   },
6382   {
6383     SPR_walk + 2,                       0,
6384     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
6385   },
6386   {
6387     SPR_walk + 3,                       0,
6388     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
6389   },
6390   {
6391     SPR_push + 0,                       0,
6392     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
6393   },
6394   {
6395     SPR_push + 1,                       0,
6396     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
6397   },
6398   {
6399     SPR_push + 2,                       0,
6400     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
6401   },
6402   {
6403     SPR_push + 3,                       0,
6404     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
6405   },
6406   {
6407     SPR_spray + 0,                      0,
6408     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
6409   },
6410   {
6411     SPR_spray + 1,                      0,
6412     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6413   },
6414   {
6415     SPR_spray + 2,                      0,
6416     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
6417   },
6418   {
6419     SPR_spray + 3,                      0,
6420     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
6421   },
6422   {
6423     SPR_walk + 0,                       1,
6424     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
6425   },
6426   {
6427     SPR_walk + 1,                       1,
6428     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
6429   },
6430   {
6431     SPR_walk + 2,                       1,
6432     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
6433   },
6434   {
6435     SPR_walk + 3,                       1,
6436     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
6437   },
6438   {
6439     SPR_push + 0,                       1,
6440     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
6441   },
6442   {
6443     SPR_push + 1,                       1,
6444     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
6445   },
6446   {
6447     SPR_push + 2,                       1,
6448     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
6449   },
6450   {
6451     SPR_push + 3,                       1,
6452     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
6453   },
6454   {
6455     SPR_spray + 0,                      1,
6456     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
6457   },
6458   {
6459     SPR_spray + 1,                      1,
6460     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6461   },
6462   {
6463     SPR_spray + 2,                      1,
6464     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
6465   },
6466   {
6467     SPR_spray + 3,                      1,
6468     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
6469   },
6470   {
6471     SPR_still,                          0,
6472     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
6473   },
6474   {
6475     SPR_still,                          1,
6476     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
6477   },
6478   {
6479     SPR_walk + 0,                       2,
6480     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
6481   },
6482   {
6483     SPR_walk + 1,                       2,
6484     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
6485   },
6486   {
6487     SPR_walk + 2,                       2,
6488     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
6489   },
6490   {
6491     SPR_walk + 3,                       2,
6492     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
6493   },
6494   {
6495     SPR_push + 0,                       2,
6496     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
6497   },
6498   {
6499     SPR_push + 1,                       2,
6500     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
6501   },
6502   {
6503     SPR_push + 2,                       2,
6504     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
6505   },
6506   {
6507     SPR_push + 3,                       2,
6508     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
6509   },
6510   {
6511     SPR_spray + 0,                      2,
6512     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
6513   },
6514   {
6515     SPR_spray + 1,                      2,
6516     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6517   },
6518   {
6519     SPR_spray + 2,                      2,
6520     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
6521   },
6522   {
6523     SPR_spray + 3,                      2,
6524     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
6525   },
6526   {
6527     SPR_walk + 0,                       3,
6528     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
6529   },
6530   {
6531     SPR_walk + 1,                       3,
6532     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
6533   },
6534   {
6535     SPR_walk + 2,                       3,
6536     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
6537   },
6538   {
6539     SPR_walk + 3,                       3,
6540     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
6541   },
6542   {
6543     SPR_push + 0,                       3,
6544     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
6545   },
6546   {
6547     SPR_push + 1,                       3,
6548     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
6549   },
6550   {
6551     SPR_push + 2,                       3,
6552     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
6553   },
6554   {
6555     SPR_push + 3,                       3,
6556     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
6557   },
6558   {
6559     SPR_spray + 0,                      3,
6560     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
6561   },
6562   {
6563     SPR_spray + 1,                      3,
6564     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6565   },
6566   {
6567     SPR_spray + 2,                      3,
6568     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
6569   },
6570   {
6571     SPR_spray + 3,                      3,
6572     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
6573   },
6574   {
6575     SPR_still,                          2,
6576     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
6577   },
6578   {
6579     SPR_still,                          3,
6580     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
6581   },
6582
6583   {
6584     -1,                                 -1,
6585     -1,                                 -1, -1
6586   }
6587 };
6588
6589 int map_element_RND_to_EM(int element_rnd)
6590 {
6591   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6592   static boolean mapping_initialized = FALSE;
6593
6594   if (!mapping_initialized)
6595   {
6596     int i;
6597
6598     /* return "Xalpha_quest" for all undefined elements in mapping array */
6599     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6600       mapping_RND_to_EM[i] = Xalpha_quest;
6601
6602     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6603       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6604         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6605           em_object_mapping_list[i].element_em;
6606
6607     mapping_initialized = TRUE;
6608   }
6609
6610   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6611     return mapping_RND_to_EM[element_rnd];
6612
6613   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6614
6615   return EL_UNKNOWN;
6616 }
6617
6618 int map_element_EM_to_RND(int element_em)
6619 {
6620   static unsigned short mapping_EM_to_RND[TILE_MAX];
6621   static boolean mapping_initialized = FALSE;
6622
6623   if (!mapping_initialized)
6624   {
6625     int i;
6626
6627     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6628     for (i = 0; i < TILE_MAX; i++)
6629       mapping_EM_to_RND[i] = EL_UNKNOWN;
6630
6631     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6632       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6633         em_object_mapping_list[i].element_rnd;
6634
6635     mapping_initialized = TRUE;
6636   }
6637
6638   if (element_em >= 0 && element_em < TILE_MAX)
6639     return mapping_EM_to_RND[element_em];
6640
6641   Error(ERR_WARN, "invalid EM level element %d", element_em);
6642
6643   return EL_UNKNOWN;
6644 }
6645
6646 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6647 {
6648   struct LevelInfo_EM *level_em = level->native_em_level;
6649   struct LEVEL *lev = level_em->lev;
6650   int i, j;
6651
6652   for (i = 0; i < TILE_MAX; i++)
6653     lev->android_array[i] = Xblank;
6654
6655   for (i = 0; i < level->num_android_clone_elements; i++)
6656   {
6657     int element_rnd = level->android_clone_element[i];
6658     int element_em = map_element_RND_to_EM(element_rnd);
6659
6660     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6661       if (em_object_mapping_list[j].element_rnd == element_rnd)
6662         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6663   }
6664 }
6665
6666 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6667 {
6668   struct LevelInfo_EM *level_em = level->native_em_level;
6669   struct LEVEL *lev = level_em->lev;
6670   int i, j;
6671
6672   level->num_android_clone_elements = 0;
6673
6674   for (i = 0; i < TILE_MAX; i++)
6675   {
6676     int element_em = lev->android_array[i];
6677     int element_rnd;
6678     boolean element_found = FALSE;
6679
6680     if (element_em == Xblank)
6681       continue;
6682
6683     element_rnd = map_element_EM_to_RND(element_em);
6684
6685     for (j = 0; j < level->num_android_clone_elements; j++)
6686       if (level->android_clone_element[j] == element_rnd)
6687         element_found = TRUE;
6688
6689     if (!element_found)
6690     {
6691       level->android_clone_element[level->num_android_clone_elements++] =
6692         element_rnd;
6693
6694       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6695         break;
6696     }
6697   }
6698
6699   if (level->num_android_clone_elements == 0)
6700   {
6701     level->num_android_clone_elements = 1;
6702     level->android_clone_element[0] = EL_EMPTY;
6703   }
6704 }
6705
6706 int map_direction_RND_to_EM(int direction)
6707 {
6708   return (direction == MV_UP    ? 0 :
6709           direction == MV_RIGHT ? 1 :
6710           direction == MV_DOWN  ? 2 :
6711           direction == MV_LEFT  ? 3 :
6712           -1);
6713 }
6714
6715 int map_direction_EM_to_RND(int direction)
6716 {
6717   return (direction == 0 ? MV_UP    :
6718           direction == 1 ? MV_RIGHT :
6719           direction == 2 ? MV_DOWN  :
6720           direction == 3 ? MV_LEFT  :
6721           MV_NONE);
6722 }
6723
6724 int map_element_RND_to_SP(int element_rnd)
6725 {
6726   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
6727
6728   if (element_rnd >= EL_SP_START &&
6729       element_rnd <= EL_SP_END)
6730     element_sp = element_rnd - EL_SP_START;
6731   else if (element_rnd == EL_EMPTY_SPACE)
6732     element_sp = 0x00;
6733   else if (element_rnd == EL_INVISIBLE_WALL)
6734     element_sp = 0x28;
6735
6736   return element_sp;
6737 }
6738
6739 int map_element_SP_to_RND(int element_sp)
6740 {
6741   int element_rnd = EL_UNKNOWN;
6742
6743   if (element_sp >= 0x00 &&
6744       element_sp <= 0x27)
6745     element_rnd = EL_SP_START + element_sp;
6746   else if (element_sp == 0x28)
6747     element_rnd = EL_INVISIBLE_WALL;
6748
6749   return element_rnd;
6750 }
6751
6752 int map_action_SP_to_RND(int action_sp)
6753 {
6754   switch (action_sp)
6755   {
6756     case actActive:             return ACTION_ACTIVE;
6757     case actImpact:             return ACTION_IMPACT;
6758     case actExploding:          return ACTION_EXPLODING;
6759     case actDigging:            return ACTION_DIGGING;
6760     case actSnapping:           return ACTION_SNAPPING;
6761     case actCollecting:         return ACTION_COLLECTING;
6762     case actPassing:            return ACTION_PASSING;
6763     case actPushing:            return ACTION_PUSHING;
6764     case actDropping:           return ACTION_DROPPING;
6765
6766     default:                    return ACTION_DEFAULT;
6767   }
6768 }
6769
6770 int get_next_element(int element)
6771 {
6772   switch (element)
6773   {
6774     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
6775     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
6776     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
6777     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
6778     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
6779     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
6780     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
6781     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
6782     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
6783     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
6784     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
6785
6786     default:                            return element;
6787   }
6788 }
6789
6790 #if 0
6791 int el_act_dir2img(int element, int action, int direction)
6792 {
6793   element = GFX_ELEMENT(element);
6794
6795   if (direction == MV_NONE)
6796     return element_info[element].graphic[action];
6797
6798   direction = MV_DIR_TO_BIT(direction);
6799
6800   return element_info[element].direction_graphic[action][direction];
6801 }
6802 #else
6803 int el_act_dir2img(int element, int action, int direction)
6804 {
6805   element = GFX_ELEMENT(element);
6806   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6807
6808   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6809   return element_info[element].direction_graphic[action][direction];
6810 }
6811 #endif
6812
6813 #if 0
6814 static int el_act_dir2crm(int element, int action, int direction)
6815 {
6816   element = GFX_ELEMENT(element);
6817
6818   if (direction == MV_NONE)
6819     return element_info[element].crumbled[action];
6820
6821   direction = MV_DIR_TO_BIT(direction);
6822
6823   return element_info[element].direction_crumbled[action][direction];
6824 }
6825 #else
6826 static int el_act_dir2crm(int element, int action, int direction)
6827 {
6828   element = GFX_ELEMENT(element);
6829   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6830
6831   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6832   return element_info[element].direction_crumbled[action][direction];
6833 }
6834 #endif
6835
6836 int el_act2img(int element, int action)
6837 {
6838   element = GFX_ELEMENT(element);
6839
6840   return element_info[element].graphic[action];
6841 }
6842
6843 int el_act2crm(int element, int action)
6844 {
6845   element = GFX_ELEMENT(element);
6846
6847   return element_info[element].crumbled[action];
6848 }
6849
6850 int el_dir2img(int element, int direction)
6851 {
6852   element = GFX_ELEMENT(element);
6853
6854   return el_act_dir2img(element, ACTION_DEFAULT, direction);
6855 }
6856
6857 int el2baseimg(int element)
6858 {
6859   return element_info[element].graphic[ACTION_DEFAULT];
6860 }
6861
6862 int el2img(int element)
6863 {
6864   element = GFX_ELEMENT(element);
6865
6866   return element_info[element].graphic[ACTION_DEFAULT];
6867 }
6868
6869 int el2edimg(int element)
6870 {
6871   element = GFX_ELEMENT(element);
6872
6873   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6874 }
6875
6876 int el2preimg(int element)
6877 {
6878   element = GFX_ELEMENT(element);
6879
6880   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6881 }
6882
6883 int el2panelimg(int element)
6884 {
6885   element = GFX_ELEMENT(element);
6886
6887   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6888 }
6889
6890 int font2baseimg(int font_nr)
6891 {
6892   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6893 }
6894
6895 int getBeltNrFromBeltElement(int element)
6896 {
6897   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6898           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6899           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6900 }
6901
6902 int getBeltNrFromBeltActiveElement(int element)
6903 {
6904   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6905           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6906           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6907 }
6908
6909 int getBeltNrFromBeltSwitchElement(int element)
6910 {
6911   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6912           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6913           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6914 }
6915
6916 int getBeltDirNrFromBeltElement(int element)
6917 {
6918   static int belt_base_element[4] =
6919   {
6920     EL_CONVEYOR_BELT_1_LEFT,
6921     EL_CONVEYOR_BELT_2_LEFT,
6922     EL_CONVEYOR_BELT_3_LEFT,
6923     EL_CONVEYOR_BELT_4_LEFT
6924   };
6925
6926   int belt_nr = getBeltNrFromBeltElement(element);
6927   int belt_dir_nr = element - belt_base_element[belt_nr];
6928
6929   return (belt_dir_nr % 3);
6930 }
6931
6932 int getBeltDirNrFromBeltSwitchElement(int element)
6933 {
6934   static int belt_base_element[4] =
6935   {
6936     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6937     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6938     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6939     EL_CONVEYOR_BELT_4_SWITCH_LEFT
6940   };
6941
6942   int belt_nr = getBeltNrFromBeltSwitchElement(element);
6943   int belt_dir_nr = element - belt_base_element[belt_nr];
6944
6945   return (belt_dir_nr % 3);
6946 }
6947
6948 int getBeltDirFromBeltElement(int element)
6949 {
6950   static int belt_move_dir[3] =
6951   {
6952     MV_LEFT,
6953     MV_NONE,
6954     MV_RIGHT
6955   };
6956
6957   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6958
6959   return belt_move_dir[belt_dir_nr];
6960 }
6961
6962 int getBeltDirFromBeltSwitchElement(int element)
6963 {
6964   static int belt_move_dir[3] =
6965   {
6966     MV_LEFT,
6967     MV_NONE,
6968     MV_RIGHT
6969   };
6970
6971   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6972
6973   return belt_move_dir[belt_dir_nr];
6974 }
6975
6976 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6977 {
6978   static int belt_base_element[4] =
6979   {
6980     EL_CONVEYOR_BELT_1_LEFT,
6981     EL_CONVEYOR_BELT_2_LEFT,
6982     EL_CONVEYOR_BELT_3_LEFT,
6983     EL_CONVEYOR_BELT_4_LEFT
6984   };
6985
6986   return belt_base_element[belt_nr] + belt_dir_nr;
6987 }
6988
6989 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6990 {
6991   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6992
6993   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6994 }
6995
6996 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6997 {
6998   static int belt_base_element[4] =
6999   {
7000     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7001     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7002     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7003     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7004   };
7005
7006   return belt_base_element[belt_nr] + belt_dir_nr;
7007 }
7008
7009 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7010 {
7011   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7012
7013   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7014 }
7015
7016 int getNumActivePlayers_EM()
7017 {
7018   int num_players = 0;
7019   int i;
7020
7021   if (!tape.playing)
7022     return -1;
7023
7024   for (i = 0; i < MAX_PLAYERS; i++)
7025     if (tape.player_participates[i])
7026       num_players++;
7027
7028   return num_players;
7029 }
7030
7031 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7032 {
7033   int game_frame_delay_value;
7034
7035   game_frame_delay_value =
7036     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7037      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7038      GameFrameDelay);
7039
7040   if (tape.playing && tape.warp_forward && !tape.pausing)
7041     game_frame_delay_value = 0;
7042
7043   return game_frame_delay_value;
7044 }
7045
7046 unsigned int InitRND(long seed)
7047 {
7048   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7049     return InitEngineRandom_EM(seed);
7050   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7051     return InitEngineRandom_SP(seed);
7052   else
7053     return InitEngineRandom_RND(seed);
7054 }
7055
7056 #if 1
7057 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7058 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7059 #endif
7060
7061 inline static int get_effective_element_EM(int tile, int frame_em)
7062 {
7063   int element             = object_mapping[tile].element_rnd;
7064   int action              = object_mapping[tile].action;
7065   boolean is_backside     = object_mapping[tile].is_backside;
7066   boolean action_removing = (action == ACTION_DIGGING ||
7067                              action == ACTION_SNAPPING ||
7068                              action == ACTION_COLLECTING);
7069
7070   if (frame_em < 7)
7071   {
7072     switch (tile)
7073     {
7074       case Yacid_splash_eB:
7075       case Yacid_splash_wB:
7076         return (frame_em > 5 ? EL_EMPTY : element);
7077
7078 #if 0
7079       case Ydiamond_stone:
7080         //  if (!game.use_native_emc_graphics_engine)
7081         return EL_ROCK;
7082 #endif
7083
7084       default:
7085         return element;
7086     }
7087   }
7088   else  /* frame_em == 7 */
7089   {
7090     switch (tile)
7091     {
7092       case Yacid_splash_eB:
7093       case Yacid_splash_wB:
7094         return EL_EMPTY;
7095
7096       case Yemerald_stone:
7097         return EL_EMERALD;
7098
7099       case Ydiamond_stone:
7100         return EL_ROCK;
7101
7102       case Xdrip_stretch:
7103       case Xdrip_stretchB:
7104       case Ydrip_s1:
7105       case Ydrip_s1B:
7106       case Xball_1B:
7107       case Xball_2:
7108       case Xball_2B:
7109       case Yball_eat:
7110       case Ykey_1_eat:
7111       case Ykey_2_eat:
7112       case Ykey_3_eat:
7113       case Ykey_4_eat:
7114       case Ykey_5_eat:
7115       case Ykey_6_eat:
7116       case Ykey_7_eat:
7117       case Ykey_8_eat:
7118       case Ylenses_eat:
7119       case Ymagnify_eat:
7120       case Ygrass_eat:
7121       case Ydirt_eat:
7122       case Xsand_stonein_1:
7123       case Xsand_stonein_2:
7124       case Xsand_stonein_3:
7125       case Xsand_stonein_4:
7126         return element;
7127
7128       default:
7129         return (is_backside || action_removing ? EL_EMPTY : element);
7130     }
7131   }
7132 }
7133
7134 inline static boolean check_linear_animation_EM(int tile)
7135 {
7136   switch (tile)
7137   {
7138     case Xsand_stonesand_1:
7139     case Xsand_stonesand_quickout_1:
7140     case Xsand_sandstone_1:
7141     case Xsand_stonein_1:
7142     case Xsand_stoneout_1:
7143     case Xboom_1:
7144     case Xdynamite_1:
7145     case Ybug_w_n:
7146     case Ybug_n_e:
7147     case Ybug_e_s:
7148     case Ybug_s_w:
7149     case Ybug_e_n:
7150     case Ybug_s_e:
7151     case Ybug_w_s:
7152     case Ybug_n_w:
7153     case Ytank_w_n:
7154     case Ytank_n_e:
7155     case Ytank_e_s:
7156     case Ytank_s_w:
7157     case Ytank_e_n:
7158     case Ytank_s_e:
7159     case Ytank_w_s:
7160     case Ytank_n_w:
7161 #if 1
7162     case Yacid_splash_eB:
7163     case Yacid_splash_wB:
7164     case Yemerald_stone:
7165 #endif
7166       return TRUE;
7167   }
7168
7169   return FALSE;
7170 }
7171
7172 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7173                                             boolean has_crumbled_graphics,
7174                                             int crumbled, int sync_frame)
7175 {
7176   /* if element can be crumbled, but certain action graphics are just empty
7177      space (like instantly snapping sand to empty space in 1 frame), do not
7178      treat these empty space graphics as crumbled graphics in EMC engine */
7179   if (crumbled == IMG_EMPTY_SPACE)
7180     has_crumbled_graphics = FALSE;
7181
7182   if (has_crumbled_graphics)
7183   {
7184     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7185     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7186                                            g_crumbled->anim_delay,
7187                                            g_crumbled->anim_mode,
7188                                            g_crumbled->anim_start_frame,
7189                                            sync_frame);
7190
7191     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7192                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7193
7194     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7195
7196     g_em->has_crumbled_graphics = TRUE;
7197   }
7198   else
7199   {
7200     g_em->crumbled_bitmap = NULL;
7201     g_em->crumbled_src_x = 0;
7202     g_em->crumbled_src_y = 0;
7203     g_em->crumbled_border_size = 0;
7204
7205     g_em->has_crumbled_graphics = FALSE;
7206   }
7207 }
7208
7209 void ResetGfxAnimation_EM(int x, int y, int tile)
7210 {
7211   GfxFrame[x][y] = 0;
7212 }
7213
7214 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7215                         int tile, int frame_em, int x, int y)
7216 {
7217   int action = object_mapping[tile].action;
7218 #if 1
7219   int direction = object_mapping[tile].direction;
7220   int effective_element = get_effective_element_EM(tile, frame_em);
7221   int graphic = (direction == MV_NONE ?
7222                  el_act2img(effective_element, action) :
7223                  el_act_dir2img(effective_element, action, direction));
7224   struct GraphicInfo *g = &graphic_info[graphic];
7225   int sync_frame;
7226 #endif
7227   boolean action_removing = (action == ACTION_DIGGING ||
7228                              action == ACTION_SNAPPING ||
7229                              action == ACTION_COLLECTING);
7230   boolean action_moving   = (action == ACTION_FALLING ||
7231                              action == ACTION_MOVING ||
7232                              action == ACTION_PUSHING ||
7233                              action == ACTION_EATING ||
7234                              action == ACTION_FILLING ||
7235                              action == ACTION_EMPTYING);
7236   boolean action_falling  = (action == ACTION_FALLING ||
7237                              action == ACTION_FILLING ||
7238                              action == ACTION_EMPTYING);
7239
7240   /* special case: graphic uses "2nd movement tile" and has defined
7241      7 frames for movement animation (or less) => use default graphic
7242      for last (8th) frame which ends the movement animation */
7243   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7244   {
7245     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
7246     graphic = (direction == MV_NONE ?
7247                el_act2img(effective_element, action) :
7248                el_act_dir2img(effective_element, action, direction));
7249
7250     g = &graphic_info[graphic];
7251   }
7252
7253 #if 0
7254   if (tile == Xsand_stonesand_1 ||
7255       tile == Xsand_stonesand_2 ||
7256       tile == Xsand_stonesand_3 ||
7257       tile == Xsand_stonesand_4)
7258     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7259 #endif
7260
7261 #if 1
7262   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7263   {
7264     GfxFrame[x][y] = 0;
7265
7266     // printf("::: resetting... [%d]\n", tile);
7267   }
7268 #else
7269   if (action_removing || check_linear_animation_EM(tile))
7270   {
7271     GfxFrame[x][y] = frame_em;
7272
7273     // printf("::: resetting... [%d]\n", tile);
7274   }
7275 #endif
7276   else if (action_moving)
7277   {
7278     boolean is_backside = object_mapping[tile].is_backside;
7279
7280     if (is_backside)
7281     {
7282       int direction = object_mapping[tile].direction;
7283       int move_dir = (action_falling ? MV_DOWN : direction);
7284
7285       GfxFrame[x][y]++;
7286
7287 #if 1
7288       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7289       if (g->double_movement && frame_em == 0)
7290       {
7291         GfxFrame[x][y] = 0;
7292
7293         // printf("::: resetting... [%d]\n", tile);
7294       }
7295 #endif
7296
7297       if (move_dir == MV_LEFT)
7298         GfxFrame[x - 1][y] = GfxFrame[x][y];
7299       else if (move_dir == MV_RIGHT)
7300         GfxFrame[x + 1][y] = GfxFrame[x][y];
7301       else if (move_dir == MV_UP)
7302         GfxFrame[x][y - 1] = GfxFrame[x][y];
7303       else if (move_dir == MV_DOWN)
7304         GfxFrame[x][y + 1] = GfxFrame[x][y];
7305     }
7306   }
7307   else
7308   {
7309     GfxFrame[x][y]++;
7310
7311     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7312     if (tile == Xsand_stonesand_quickout_1 ||
7313         tile == Xsand_stonesand_quickout_2)
7314       GfxFrame[x][y]++;
7315   }
7316
7317 #if 0
7318   if (tile == Xsand_stonesand_1 ||
7319       tile == Xsand_stonesand_2 ||
7320       tile == Xsand_stonesand_3 ||
7321       tile == Xsand_stonesand_4)
7322     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7323 #endif
7324
7325 #if 1
7326   if (graphic_info[graphic].anim_global_sync)
7327     sync_frame = FrameCounter;
7328   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7329     sync_frame = GfxFrame[x][y];
7330   else
7331     sync_frame = 0;     /* playfield border (pseudo steel) */
7332
7333   SetRandomAnimationValue(x, y);
7334
7335   int frame = getAnimationFrame(g->anim_frames,
7336                                 g->anim_delay,
7337                                 g->anim_mode,
7338                                 g->anim_start_frame,
7339                                 sync_frame);
7340
7341   g_em->unique_identifier =
7342     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7343 #endif
7344 }
7345
7346 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7347                                   int tile, int frame_em, int x, int y)
7348 {
7349   int action = object_mapping[tile].action;
7350   int direction = object_mapping[tile].direction;
7351   boolean is_backside = object_mapping[tile].is_backside;
7352   int effective_element = get_effective_element_EM(tile, frame_em);
7353 #if 1
7354   int effective_action = action;
7355 #else
7356   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7357 #endif
7358   int graphic = (direction == MV_NONE ?
7359                  el_act2img(effective_element, effective_action) :
7360                  el_act_dir2img(effective_element, effective_action,
7361                                 direction));
7362   int crumbled = (direction == MV_NONE ?
7363                   el_act2crm(effective_element, effective_action) :
7364                   el_act_dir2crm(effective_element, effective_action,
7365                                  direction));
7366   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7367   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7368   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7369   struct GraphicInfo *g = &graphic_info[graphic];
7370 #if 0
7371   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7372 #endif
7373   int sync_frame;
7374
7375   /* special case: graphic uses "2nd movement tile" and has defined
7376      7 frames for movement animation (or less) => use default graphic
7377      for last (8th) frame which ends the movement animation */
7378   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7379   {
7380     effective_action = ACTION_DEFAULT;
7381     graphic = (direction == MV_NONE ?
7382                el_act2img(effective_element, effective_action) :
7383                el_act_dir2img(effective_element, effective_action,
7384                               direction));
7385     crumbled = (direction == MV_NONE ?
7386                 el_act2crm(effective_element, effective_action) :
7387                 el_act_dir2crm(effective_element, effective_action,
7388                                direction));
7389
7390     g = &graphic_info[graphic];
7391   }
7392
7393 #if 0
7394   if (frame_em == 7)
7395     return;
7396 #endif
7397
7398
7399 #if 0
7400   if (frame_em == 0)    /* reset animation frame for certain elements */
7401   {
7402     if (check_linear_animation_EM(tile))
7403       GfxFrame[x][y] = 0;
7404   }
7405 #endif
7406
7407   if (graphic_info[graphic].anim_global_sync)
7408     sync_frame = FrameCounter;
7409   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7410     sync_frame = GfxFrame[x][y];
7411   else
7412     sync_frame = 0;     /* playfield border (pseudo steel) */
7413
7414   SetRandomAnimationValue(x, y);
7415
7416 #if 0
7417   int i = tile;
7418   int j = frame_em;
7419   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7420                         i == Xdrip_stretchB ? 7 :
7421                         i == Ydrip_s2 ? j + 8 :
7422                         i == Ydrip_s2B ? j + 8 :
7423                         i == Xacid_1 ? 0 :
7424                         i == Xacid_2 ? 10 :
7425                         i == Xacid_3 ? 20 :
7426                         i == Xacid_4 ? 30 :
7427                         i == Xacid_5 ? 40 :
7428                         i == Xacid_6 ? 50 :
7429                         i == Xacid_7 ? 60 :
7430                         i == Xacid_8 ? 70 :
7431                         i == Xfake_acid_1 ? 0 :
7432                         i == Xfake_acid_2 ? 10 :
7433                         i == Xfake_acid_3 ? 20 :
7434                         i == Xfake_acid_4 ? 30 :
7435                         i == Xfake_acid_5 ? 40 :
7436                         i == Xfake_acid_6 ? 50 :
7437                         i == Xfake_acid_7 ? 60 :
7438                         i == Xfake_acid_8 ? 70 :
7439                         i == Xball_2 ? 7 :
7440                         i == Xball_2B ? j + 8 :
7441                         i == Yball_eat ? j + 1 :
7442                         i == Ykey_1_eat ? j + 1 :
7443                         i == Ykey_2_eat ? j + 1 :
7444                         i == Ykey_3_eat ? j + 1 :
7445                         i == Ykey_4_eat ? j + 1 :
7446                         i == Ykey_5_eat ? j + 1 :
7447                         i == Ykey_6_eat ? j + 1 :
7448                         i == Ykey_7_eat ? j + 1 :
7449                         i == Ykey_8_eat ? j + 1 :
7450                         i == Ylenses_eat ? j + 1 :
7451                         i == Ymagnify_eat ? j + 1 :
7452                         i == Ygrass_eat ? j + 1 :
7453                         i == Ydirt_eat ? j + 1 :
7454                         i == Xamoeba_1 ? 0 :
7455                         i == Xamoeba_2 ? 1 :
7456                         i == Xamoeba_3 ? 2 :
7457                         i == Xamoeba_4 ? 3 :
7458                         i == Xamoeba_5 ? 0 :
7459                         i == Xamoeba_6 ? 1 :
7460                         i == Xamoeba_7 ? 2 :
7461                         i == Xamoeba_8 ? 3 :
7462                         i == Xexit_2 ? j + 8 :
7463                         i == Xexit_3 ? j + 16 :
7464                         i == Xdynamite_1 ? 0 :
7465                         i == Xdynamite_2 ? 8 :
7466                         i == Xdynamite_3 ? 16 :
7467                         i == Xdynamite_4 ? 24 :
7468                         i == Xsand_stonein_1 ? j + 1 :
7469                         i == Xsand_stonein_2 ? j + 9 :
7470                         i == Xsand_stonein_3 ? j + 17 :
7471                         i == Xsand_stonein_4 ? j + 25 :
7472                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7473                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7474                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7475                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7476                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7477                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7478                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7479                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7480                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7481                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7482                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7483                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7484                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7485                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7486                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7487                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7488                         i == Xboom_bug && j == 1 ? 2 :
7489                         i == Xboom_bug && j == 2 ? 2 :
7490                         i == Xboom_bug && j == 3 ? 4 :
7491                         i == Xboom_bug && j == 4 ? 4 :
7492                         i == Xboom_bug && j == 5 ? 2 :
7493                         i == Xboom_bug && j == 6 ? 2 :
7494                         i == Xboom_bug && j == 7 ? 0 :
7495                         i == Xboom_bomb && j == 1 ? 2 :
7496                         i == Xboom_bomb && j == 2 ? 2 :
7497                         i == Xboom_bomb && j == 3 ? 4 :
7498                         i == Xboom_bomb && j == 4 ? 4 :
7499                         i == Xboom_bomb && j == 5 ? 2 :
7500                         i == Xboom_bomb && j == 6 ? 2 :
7501                         i == Xboom_bomb && j == 7 ? 0 :
7502                         i == Xboom_android && j == 7 ? 6 :
7503                         i == Xboom_1 && j == 1 ? 2 :
7504                         i == Xboom_1 && j == 2 ? 2 :
7505                         i == Xboom_1 && j == 3 ? 4 :
7506                         i == Xboom_1 && j == 4 ? 4 :
7507                         i == Xboom_1 && j == 5 ? 6 :
7508                         i == Xboom_1 && j == 6 ? 6 :
7509                         i == Xboom_1 && j == 7 ? 8 :
7510                         i == Xboom_2 && j == 0 ? 8 :
7511                         i == Xboom_2 && j == 1 ? 8 :
7512                         i == Xboom_2 && j == 2 ? 10 :
7513                         i == Xboom_2 && j == 3 ? 10 :
7514                         i == Xboom_2 && j == 4 ? 10 :
7515                         i == Xboom_2 && j == 5 ? 12 :
7516                         i == Xboom_2 && j == 6 ? 12 :
7517                         i == Xboom_2 && j == 7 ? 12 :
7518 #if 0
7519                         special_animation && j == 4 ? 3 :
7520                         effective_action != action ? 0 :
7521 #endif
7522                         j);
7523 #endif
7524
7525 #if 0
7526   int xxx_effective_action;
7527   int xxx_has_action_graphics;
7528
7529   {
7530     int element = object_mapping[i].element_rnd;
7531     int action = object_mapping[i].action;
7532     int direction = object_mapping[i].direction;
7533     boolean is_backside = object_mapping[i].is_backside;
7534 #if 0
7535     boolean action_removing = (action == ACTION_DIGGING ||
7536                                action == ACTION_SNAPPING ||
7537                                action == ACTION_COLLECTING);
7538 #endif
7539     boolean action_exploding = ((action == ACTION_EXPLODING ||
7540                                  action == ACTION_SMASHED_BY_ROCK ||
7541                                  action == ACTION_SMASHED_BY_SPRING) &&
7542                                 element != EL_DIAMOND);
7543     boolean action_active = (action == ACTION_ACTIVE);
7544     boolean action_other = (action == ACTION_OTHER);
7545
7546     {
7547 #if 1
7548       int effective_element = get_effective_element_EM(i, j);
7549 #else
7550       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7551                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7552                                j < 7 ? element :
7553                                i == Xdrip_stretch ? element :
7554                                i == Xdrip_stretchB ? element :
7555                                i == Ydrip_s1 ? element :
7556                                i == Ydrip_s1B ? element :
7557                                i == Xball_1B ? element :
7558                                i == Xball_2 ? element :
7559                                i == Xball_2B ? element :
7560                                i == Yball_eat ? element :
7561                                i == Ykey_1_eat ? element :
7562                                i == Ykey_2_eat ? element :
7563                                i == Ykey_3_eat ? element :
7564                                i == Ykey_4_eat ? element :
7565                                i == Ykey_5_eat ? element :
7566                                i == Ykey_6_eat ? element :
7567                                i == Ykey_7_eat ? element :
7568                                i == Ykey_8_eat ? element :
7569                                i == Ylenses_eat ? element :
7570                                i == Ymagnify_eat ? element :
7571                                i == Ygrass_eat ? element :
7572                                i == Ydirt_eat ? element :
7573                                i == Yemerald_stone ? EL_EMERALD :
7574                                i == Ydiamond_stone ? EL_ROCK :
7575                                i == Xsand_stonein_1 ? element :
7576                                i == Xsand_stonein_2 ? element :
7577                                i == Xsand_stonein_3 ? element :
7578                                i == Xsand_stonein_4 ? element :
7579                                is_backside ? EL_EMPTY :
7580                                action_removing ? EL_EMPTY :
7581                                element);
7582 #endif
7583       int effective_action = (j < 7 ? action :
7584                               i == Xdrip_stretch ? action :
7585                               i == Xdrip_stretchB ? action :
7586                               i == Ydrip_s1 ? action :
7587                               i == Ydrip_s1B ? action :
7588                               i == Xball_1B ? action :
7589                               i == Xball_2 ? action :
7590                               i == Xball_2B ? action :
7591                               i == Yball_eat ? action :
7592                               i == Ykey_1_eat ? action :
7593                               i == Ykey_2_eat ? action :
7594                               i == Ykey_3_eat ? action :
7595                               i == Ykey_4_eat ? action :
7596                               i == Ykey_5_eat ? action :
7597                               i == Ykey_6_eat ? action :
7598                               i == Ykey_7_eat ? action :
7599                               i == Ykey_8_eat ? action :
7600                               i == Ylenses_eat ? action :
7601                               i == Ymagnify_eat ? action :
7602                               i == Ygrass_eat ? action :
7603                               i == Ydirt_eat ? action :
7604                               i == Xsand_stonein_1 ? action :
7605                               i == Xsand_stonein_2 ? action :
7606                               i == Xsand_stonein_3 ? action :
7607                               i == Xsand_stonein_4 ? action :
7608                               i == Xsand_stoneout_1 ? action :
7609                               i == Xsand_stoneout_2 ? action :
7610                               i == Xboom_android ? ACTION_EXPLODING :
7611                               action_exploding ? ACTION_EXPLODING :
7612                               action_active ? action :
7613                               action_other ? action :
7614                               ACTION_DEFAULT);
7615       int graphic = (el_act_dir2img(effective_element, effective_action,
7616                                     direction));
7617       int crumbled = (el_act_dir2crm(effective_element, effective_action,
7618                                      direction));
7619       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7620       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7621       boolean has_action_graphics = (graphic != base_graphic);
7622       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7623       struct GraphicInfo *g = &graphic_info[graphic];
7624 #if 0
7625       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7626 #endif
7627       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7628       Bitmap *src_bitmap;
7629       int src_x, src_y;
7630       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7631       boolean special_animation = (action != ACTION_DEFAULT &&
7632                                    g->anim_frames == 3 &&
7633                                    g->anim_delay == 2 &&
7634                                    g->anim_mode & ANIM_LINEAR);
7635       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7636                         i == Xdrip_stretchB ? 7 :
7637                         i == Ydrip_s2 ? j + 8 :
7638                         i == Ydrip_s2B ? j + 8 :
7639                         i == Xacid_1 ? 0 :
7640                         i == Xacid_2 ? 10 :
7641                         i == Xacid_3 ? 20 :
7642                         i == Xacid_4 ? 30 :
7643                         i == Xacid_5 ? 40 :
7644                         i == Xacid_6 ? 50 :
7645                         i == Xacid_7 ? 60 :
7646                         i == Xacid_8 ? 70 :
7647                         i == Xfake_acid_1 ? 0 :
7648                         i == Xfake_acid_2 ? 10 :
7649                         i == Xfake_acid_3 ? 20 :
7650                         i == Xfake_acid_4 ? 30 :
7651                         i == Xfake_acid_5 ? 40 :
7652                         i == Xfake_acid_6 ? 50 :
7653                         i == Xfake_acid_7 ? 60 :
7654                         i == Xfake_acid_8 ? 70 :
7655                         i == Xball_2 ? 7 :
7656                         i == Xball_2B ? j + 8 :
7657                         i == Yball_eat ? j + 1 :
7658                         i == Ykey_1_eat ? j + 1 :
7659                         i == Ykey_2_eat ? j + 1 :
7660                         i == Ykey_3_eat ? j + 1 :
7661                         i == Ykey_4_eat ? j + 1 :
7662                         i == Ykey_5_eat ? j + 1 :
7663                         i == Ykey_6_eat ? j + 1 :
7664                         i == Ykey_7_eat ? j + 1 :
7665                         i == Ykey_8_eat ? j + 1 :
7666                         i == Ylenses_eat ? j + 1 :
7667                         i == Ymagnify_eat ? j + 1 :
7668                         i == Ygrass_eat ? j + 1 :
7669                         i == Ydirt_eat ? j + 1 :
7670                         i == Xamoeba_1 ? 0 :
7671                         i == Xamoeba_2 ? 1 :
7672                         i == Xamoeba_3 ? 2 :
7673                         i == Xamoeba_4 ? 3 :
7674                         i == Xamoeba_5 ? 0 :
7675                         i == Xamoeba_6 ? 1 :
7676                         i == Xamoeba_7 ? 2 :
7677                         i == Xamoeba_8 ? 3 :
7678                         i == Xexit_2 ? j + 8 :
7679                         i == Xexit_3 ? j + 16 :
7680                         i == Xdynamite_1 ? 0 :
7681                         i == Xdynamite_2 ? 8 :
7682                         i == Xdynamite_3 ? 16 :
7683                         i == Xdynamite_4 ? 24 :
7684                         i == Xsand_stonein_1 ? j + 1 :
7685                         i == Xsand_stonein_2 ? j + 9 :
7686                         i == Xsand_stonein_3 ? j + 17 :
7687                         i == Xsand_stonein_4 ? j + 25 :
7688                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7689                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7690                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7691                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7692                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7693                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7694                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7695                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7696                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7697                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7698                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7699                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7700                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7701                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7702                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7703                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7704                         i == Xboom_bug && j == 1 ? 2 :
7705                         i == Xboom_bug && j == 2 ? 2 :
7706                         i == Xboom_bug && j == 3 ? 4 :
7707                         i == Xboom_bug && j == 4 ? 4 :
7708                         i == Xboom_bug && j == 5 ? 2 :
7709                         i == Xboom_bug && j == 6 ? 2 :
7710                         i == Xboom_bug && j == 7 ? 0 :
7711                         i == Xboom_bomb && j == 1 ? 2 :
7712                         i == Xboom_bomb && j == 2 ? 2 :
7713                         i == Xboom_bomb && j == 3 ? 4 :
7714                         i == Xboom_bomb && j == 4 ? 4 :
7715                         i == Xboom_bomb && j == 5 ? 2 :
7716                         i == Xboom_bomb && j == 6 ? 2 :
7717                         i == Xboom_bomb && j == 7 ? 0 :
7718                         i == Xboom_android && j == 7 ? 6 :
7719                         i == Xboom_1 && j == 1 ? 2 :
7720                         i == Xboom_1 && j == 2 ? 2 :
7721                         i == Xboom_1 && j == 3 ? 4 :
7722                         i == Xboom_1 && j == 4 ? 4 :
7723                         i == Xboom_1 && j == 5 ? 6 :
7724                         i == Xboom_1 && j == 6 ? 6 :
7725                         i == Xboom_1 && j == 7 ? 8 :
7726                         i == Xboom_2 && j == 0 ? 8 :
7727                         i == Xboom_2 && j == 1 ? 8 :
7728                         i == Xboom_2 && j == 2 ? 10 :
7729                         i == Xboom_2 && j == 3 ? 10 :
7730                         i == Xboom_2 && j == 4 ? 10 :
7731                         i == Xboom_2 && j == 5 ? 12 :
7732                         i == Xboom_2 && j == 6 ? 12 :
7733                         i == Xboom_2 && j == 7 ? 12 :
7734                         special_animation && j == 4 ? 3 :
7735                         effective_action != action ? 0 :
7736                         j);
7737
7738       xxx_effective_action = effective_action;
7739       xxx_has_action_graphics = has_action_graphics;
7740     }
7741   }
7742 #endif
7743
7744   int frame = getAnimationFrame(g->anim_frames,
7745                                 g->anim_delay,
7746                                 g->anim_mode,
7747                                 g->anim_start_frame,
7748                                 sync_frame);
7749
7750
7751 #if 0
7752   return;
7753 #endif
7754
7755 #if 0
7756   if (frame_em == 7)
7757     return;
7758 #endif
7759
7760 #if 0
7761   int old_src_x = g_em->src_x;
7762   int old_src_y = g_em->src_y;
7763 #endif
7764
7765 #if 1
7766   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7767                       g->double_movement && is_backside);
7768 #else
7769   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7770                       &g_em->src_x, &g_em->src_y, FALSE);
7771 #endif
7772
7773
7774 #if 0
7775   if (tile == Ydiamond_stone)
7776     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7777            frame_em,
7778            g->anim_frames,
7779            g->anim_delay,
7780            g->anim_mode,
7781            g->anim_start_frame,
7782            sync_frame,
7783            frame,
7784            g_em->src_x, g_em->src_y,
7785            g_em->src_offset_x, g_em->src_offset_y,
7786            g_em->dst_offset_x, g_em->dst_offset_y,
7787            graphic);
7788 #endif
7789
7790
7791 #if 0
7792   return;
7793 #endif
7794
7795 #if 0
7796   if (frame_em == 7)
7797   {
7798     if (graphic == IMG_BUG_MOVING_RIGHT)
7799       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7800              g->double_movement, is_backside,
7801              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7802
7803     return;
7804   }
7805 #endif
7806
7807
7808 #if 0
7809   g_em->src_offset_x = 0;
7810   g_em->src_offset_y = 0;
7811   g_em->dst_offset_x = 0;
7812   g_em->dst_offset_y = 0;
7813   g_em->width  = TILEX;
7814   g_em->height = TILEY;
7815
7816   g_em->preserve_background = FALSE;
7817 #endif
7818
7819   /* (updating the "crumbled" graphic definitions is probably not really needed,
7820      as animations for crumbled graphics can't be longer than one EMC cycle) */
7821 #if 1
7822   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7823                            sync_frame);
7824
7825 #else
7826
7827   g_em->crumbled_bitmap = NULL;
7828   g_em->crumbled_src_x = 0;
7829   g_em->crumbled_src_y = 0;
7830
7831   g_em->has_crumbled_graphics = FALSE;
7832
7833   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7834   {
7835     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7836                                            g_crumbled->anim_delay,
7837                                            g_crumbled->anim_mode,
7838                                            g_crumbled->anim_start_frame,
7839                                            sync_frame);
7840
7841     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7842                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7843
7844     g_em->has_crumbled_graphics = TRUE;
7845   }
7846 #endif
7847
7848 #if 0
7849  {
7850    int effective_action = xxx_effective_action;
7851    int has_action_graphics = xxx_has_action_graphics;
7852
7853       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7854                                    effective_action == ACTION_MOVING  ||
7855                                    effective_action == ACTION_PUSHING ||
7856                                    effective_action == ACTION_EATING)) ||
7857           (!has_action_graphics && (effective_action == ACTION_FILLING ||
7858                                     effective_action == ACTION_EMPTYING)))
7859       {
7860         int move_dir =
7861           (effective_action == ACTION_FALLING ||
7862            effective_action == ACTION_FILLING ||
7863            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7864         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7865         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
7866         int num_steps = (i == Ydrip_s1  ? 16 :
7867                          i == Ydrip_s1B ? 16 :
7868                          i == Ydrip_s2  ? 16 :
7869                          i == Ydrip_s2B ? 16 :
7870                          i == Xsand_stonein_1 ? 32 :
7871                          i == Xsand_stonein_2 ? 32 :
7872                          i == Xsand_stonein_3 ? 32 :
7873                          i == Xsand_stonein_4 ? 32 :
7874                          i == Xsand_stoneout_1 ? 16 :
7875                          i == Xsand_stoneout_2 ? 16 : 8);
7876         int cx = ABS(dx) * (TILEX / num_steps);
7877         int cy = ABS(dy) * (TILEY / num_steps);
7878         int step_frame = (i == Ydrip_s2         ? j + 8 :
7879                           i == Ydrip_s2B        ? j + 8 :
7880                           i == Xsand_stonein_2  ? j + 8 :
7881                           i == Xsand_stonein_3  ? j + 16 :
7882                           i == Xsand_stonein_4  ? j + 24 :
7883                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7884         int step = (is_backside ? step_frame : num_steps - step_frame);
7885
7886         if (is_backside)        /* tile where movement starts */
7887         {
7888           if (dx < 0 || dy < 0)
7889           {
7890             g_em->src_offset_x = cx * step;
7891             g_em->src_offset_y = cy * step;
7892           }
7893           else
7894           {
7895             g_em->dst_offset_x = cx * step;
7896             g_em->dst_offset_y = cy * step;
7897           }
7898         }
7899         else                    /* tile where movement ends */
7900         {
7901           if (dx < 0 || dy < 0)
7902           {
7903             g_em->dst_offset_x = cx * step;
7904             g_em->dst_offset_y = cy * step;
7905           }
7906           else
7907           {
7908             g_em->src_offset_x = cx * step;
7909             g_em->src_offset_y = cy * step;
7910           }
7911         }
7912
7913         g_em->width  = TILEX - cx * step;
7914         g_em->height = TILEY - cy * step;
7915       }
7916
7917       /* create unique graphic identifier to decide if tile must be redrawn */
7918       /* bit 31 - 16 (16 bit): EM style graphic
7919          bit 15 - 12 ( 4 bit): EM style frame
7920          bit 11 -  6 ( 6 bit): graphic width
7921          bit  5 -  0 ( 6 bit): graphic height */
7922       g_em->unique_identifier =
7923         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7924  }
7925 #endif
7926
7927 }
7928
7929 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7930                                   int player_nr, int anim, int frame_em)
7931 {
7932   int element   = player_mapping[player_nr][anim].element_rnd;
7933   int action    = player_mapping[player_nr][anim].action;
7934   int direction = player_mapping[player_nr][anim].direction;
7935   int graphic = (direction == MV_NONE ?
7936                  el_act2img(element, action) :
7937                  el_act_dir2img(element, action, direction));
7938   struct GraphicInfo *g = &graphic_info[graphic];
7939   int sync_frame;
7940
7941   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7942
7943   stored_player[player_nr].StepFrame = frame_em;
7944
7945   sync_frame = stored_player[player_nr].Frame;
7946
7947   int frame = getAnimationFrame(g->anim_frames,
7948                                 g->anim_delay,
7949                                 g->anim_mode,
7950                                 g->anim_start_frame,
7951                                 sync_frame);
7952
7953   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7954                       &g_em->src_x, &g_em->src_y, FALSE);
7955
7956 #if 0
7957   printf("::: %d: %d, %d [%d]\n",
7958          player_nr,
7959          stored_player[player_nr].Frame,
7960          stored_player[player_nr].StepFrame,
7961          FrameCounter);
7962 #endif
7963 }
7964
7965 void InitGraphicInfo_EM(void)
7966 {
7967 #if 0
7968   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7969   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7970 #endif
7971   int i, j, p;
7972
7973 #if DEBUG_EM_GFX
7974   int num_em_gfx_errors = 0;
7975
7976   if (graphic_info_em_object[0][0].bitmap == NULL)
7977   {
7978     /* EM graphics not yet initialized in em_open_all() */
7979
7980     return;
7981   }
7982
7983   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7984 #endif
7985
7986   /* always start with reliable default values */
7987   for (i = 0; i < TILE_MAX; i++)
7988   {
7989     object_mapping[i].element_rnd = EL_UNKNOWN;
7990     object_mapping[i].is_backside = FALSE;
7991     object_mapping[i].action = ACTION_DEFAULT;
7992     object_mapping[i].direction = MV_NONE;
7993   }
7994
7995   /* always start with reliable default values */
7996   for (p = 0; p < MAX_PLAYERS; p++)
7997   {
7998     for (i = 0; i < SPR_MAX; i++)
7999     {
8000       player_mapping[p][i].element_rnd = EL_UNKNOWN;
8001       player_mapping[p][i].action = ACTION_DEFAULT;
8002       player_mapping[p][i].direction = MV_NONE;
8003     }
8004   }
8005
8006   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8007   {
8008     int e = em_object_mapping_list[i].element_em;
8009
8010     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8011     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8012
8013     if (em_object_mapping_list[i].action != -1)
8014       object_mapping[e].action = em_object_mapping_list[i].action;
8015
8016     if (em_object_mapping_list[i].direction != -1)
8017       object_mapping[e].direction =
8018         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8019   }
8020
8021   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8022   {
8023     int a = em_player_mapping_list[i].action_em;
8024     int p = em_player_mapping_list[i].player_nr;
8025
8026     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8027
8028     if (em_player_mapping_list[i].action != -1)
8029       player_mapping[p][a].action = em_player_mapping_list[i].action;
8030
8031     if (em_player_mapping_list[i].direction != -1)
8032       player_mapping[p][a].direction =
8033         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8034   }
8035
8036   for (i = 0; i < TILE_MAX; i++)
8037   {
8038     int element = object_mapping[i].element_rnd;
8039     int action = object_mapping[i].action;
8040     int direction = object_mapping[i].direction;
8041     boolean is_backside = object_mapping[i].is_backside;
8042 #if 0
8043     boolean action_removing = (action == ACTION_DIGGING ||
8044                                action == ACTION_SNAPPING ||
8045                                action == ACTION_COLLECTING);
8046 #endif
8047     boolean action_exploding = ((action == ACTION_EXPLODING ||
8048                                  action == ACTION_SMASHED_BY_ROCK ||
8049                                  action == ACTION_SMASHED_BY_SPRING) &&
8050                                 element != EL_DIAMOND);
8051     boolean action_active = (action == ACTION_ACTIVE);
8052     boolean action_other = (action == ACTION_OTHER);
8053
8054     for (j = 0; j < 8; j++)
8055     {
8056 #if 1
8057       int effective_element = get_effective_element_EM(i, j);
8058 #else
8059       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8060                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8061                                j < 7 ? element :
8062                                i == Xdrip_stretch ? element :
8063                                i == Xdrip_stretchB ? element :
8064                                i == Ydrip_s1 ? element :
8065                                i == Ydrip_s1B ? element :
8066                                i == Xball_1B ? element :
8067                                i == Xball_2 ? element :
8068                                i == Xball_2B ? element :
8069                                i == Yball_eat ? element :
8070                                i == Ykey_1_eat ? element :
8071                                i == Ykey_2_eat ? element :
8072                                i == Ykey_3_eat ? element :
8073                                i == Ykey_4_eat ? element :
8074                                i == Ykey_5_eat ? element :
8075                                i == Ykey_6_eat ? element :
8076                                i == Ykey_7_eat ? element :
8077                                i == Ykey_8_eat ? element :
8078                                i == Ylenses_eat ? element :
8079                                i == Ymagnify_eat ? element :
8080                                i == Ygrass_eat ? element :
8081                                i == Ydirt_eat ? element :
8082                                i == Yemerald_stone ? EL_EMERALD :
8083                                i == Ydiamond_stone ? EL_ROCK :
8084                                i == Xsand_stonein_1 ? element :
8085                                i == Xsand_stonein_2 ? element :
8086                                i == Xsand_stonein_3 ? element :
8087                                i == Xsand_stonein_4 ? element :
8088                                is_backside ? EL_EMPTY :
8089                                action_removing ? EL_EMPTY :
8090                                element);
8091 #endif
8092       int effective_action = (j < 7 ? action :
8093                               i == Xdrip_stretch ? action :
8094                               i == Xdrip_stretchB ? action :
8095                               i == Ydrip_s1 ? action :
8096                               i == Ydrip_s1B ? action :
8097                               i == Xball_1B ? action :
8098                               i == Xball_2 ? action :
8099                               i == Xball_2B ? action :
8100                               i == Yball_eat ? action :
8101                               i == Ykey_1_eat ? action :
8102                               i == Ykey_2_eat ? action :
8103                               i == Ykey_3_eat ? action :
8104                               i == Ykey_4_eat ? action :
8105                               i == Ykey_5_eat ? action :
8106                               i == Ykey_6_eat ? action :
8107                               i == Ykey_7_eat ? action :
8108                               i == Ykey_8_eat ? action :
8109                               i == Ylenses_eat ? action :
8110                               i == Ymagnify_eat ? action :
8111                               i == Ygrass_eat ? action :
8112                               i == Ydirt_eat ? action :
8113                               i == Xsand_stonein_1 ? action :
8114                               i == Xsand_stonein_2 ? action :
8115                               i == Xsand_stonein_3 ? action :
8116                               i == Xsand_stonein_4 ? action :
8117                               i == Xsand_stoneout_1 ? action :
8118                               i == Xsand_stoneout_2 ? action :
8119                               i == Xboom_android ? ACTION_EXPLODING :
8120                               action_exploding ? ACTION_EXPLODING :
8121                               action_active ? action :
8122                               action_other ? action :
8123                               ACTION_DEFAULT);
8124       int graphic = (el_act_dir2img(effective_element, effective_action,
8125                                     direction));
8126       int crumbled = (el_act_dir2crm(effective_element, effective_action,
8127                                      direction));
8128       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8129       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8130       boolean has_action_graphics = (graphic != base_graphic);
8131       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8132       struct GraphicInfo *g = &graphic_info[graphic];
8133 #if 0
8134       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8135 #endif
8136       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8137       Bitmap *src_bitmap;
8138       int src_x, src_y;
8139       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8140       boolean special_animation = (action != ACTION_DEFAULT &&
8141                                    g->anim_frames == 3 &&
8142                                    g->anim_delay == 2 &&
8143                                    g->anim_mode & ANIM_LINEAR);
8144       int sync_frame = (i == Xdrip_stretch ? 7 :
8145                         i == Xdrip_stretchB ? 7 :
8146                         i == Ydrip_s2 ? j + 8 :
8147                         i == Ydrip_s2B ? j + 8 :
8148                         i == Xacid_1 ? 0 :
8149                         i == Xacid_2 ? 10 :
8150                         i == Xacid_3 ? 20 :
8151                         i == Xacid_4 ? 30 :
8152                         i == Xacid_5 ? 40 :
8153                         i == Xacid_6 ? 50 :
8154                         i == Xacid_7 ? 60 :
8155                         i == Xacid_8 ? 70 :
8156                         i == Xfake_acid_1 ? 0 :
8157                         i == Xfake_acid_2 ? 10 :
8158                         i == Xfake_acid_3 ? 20 :
8159                         i == Xfake_acid_4 ? 30 :
8160                         i == Xfake_acid_5 ? 40 :
8161                         i == Xfake_acid_6 ? 50 :
8162                         i == Xfake_acid_7 ? 60 :
8163                         i == Xfake_acid_8 ? 70 :
8164                         i == Xball_2 ? 7 :
8165                         i == Xball_2B ? j + 8 :
8166                         i == Yball_eat ? j + 1 :
8167                         i == Ykey_1_eat ? j + 1 :
8168                         i == Ykey_2_eat ? j + 1 :
8169                         i == Ykey_3_eat ? j + 1 :
8170                         i == Ykey_4_eat ? j + 1 :
8171                         i == Ykey_5_eat ? j + 1 :
8172                         i == Ykey_6_eat ? j + 1 :
8173                         i == Ykey_7_eat ? j + 1 :
8174                         i == Ykey_8_eat ? j + 1 :
8175                         i == Ylenses_eat ? j + 1 :
8176                         i == Ymagnify_eat ? j + 1 :
8177                         i == Ygrass_eat ? j + 1 :
8178                         i == Ydirt_eat ? j + 1 :
8179                         i == Xamoeba_1 ? 0 :
8180                         i == Xamoeba_2 ? 1 :
8181                         i == Xamoeba_3 ? 2 :
8182                         i == Xamoeba_4 ? 3 :
8183                         i == Xamoeba_5 ? 0 :
8184                         i == Xamoeba_6 ? 1 :
8185                         i == Xamoeba_7 ? 2 :
8186                         i == Xamoeba_8 ? 3 :
8187                         i == Xexit_2 ? j + 8 :
8188                         i == Xexit_3 ? j + 16 :
8189                         i == Xdynamite_1 ? 0 :
8190                         i == Xdynamite_2 ? 8 :
8191                         i == Xdynamite_3 ? 16 :
8192                         i == Xdynamite_4 ? 24 :
8193                         i == Xsand_stonein_1 ? j + 1 :
8194                         i == Xsand_stonein_2 ? j + 9 :
8195                         i == Xsand_stonein_3 ? j + 17 :
8196                         i == Xsand_stonein_4 ? j + 25 :
8197                         i == Xsand_stoneout_1 && j == 0 ? 0 :
8198                         i == Xsand_stoneout_1 && j == 1 ? 0 :
8199                         i == Xsand_stoneout_1 && j == 2 ? 1 :
8200                         i == Xsand_stoneout_1 && j == 3 ? 2 :
8201                         i == Xsand_stoneout_1 && j == 4 ? 2 :
8202                         i == Xsand_stoneout_1 && j == 5 ? 3 :
8203                         i == Xsand_stoneout_1 && j == 6 ? 4 :
8204                         i == Xsand_stoneout_1 && j == 7 ? 4 :
8205                         i == Xsand_stoneout_2 && j == 0 ? 5 :
8206                         i == Xsand_stoneout_2 && j == 1 ? 6 :
8207                         i == Xsand_stoneout_2 && j == 2 ? 7 :
8208                         i == Xsand_stoneout_2 && j == 3 ? 8 :
8209                         i == Xsand_stoneout_2 && j == 4 ? 9 :
8210                         i == Xsand_stoneout_2 && j == 5 ? 11 :
8211                         i == Xsand_stoneout_2 && j == 6 ? 13 :
8212                         i == Xsand_stoneout_2 && j == 7 ? 15 :
8213                         i == Xboom_bug && j == 1 ? 2 :
8214                         i == Xboom_bug && j == 2 ? 2 :
8215                         i == Xboom_bug && j == 3 ? 4 :
8216                         i == Xboom_bug && j == 4 ? 4 :
8217                         i == Xboom_bug && j == 5 ? 2 :
8218                         i == Xboom_bug && j == 6 ? 2 :
8219                         i == Xboom_bug && j == 7 ? 0 :
8220                         i == Xboom_bomb && j == 1 ? 2 :
8221                         i == Xboom_bomb && j == 2 ? 2 :
8222                         i == Xboom_bomb && j == 3 ? 4 :
8223                         i == Xboom_bomb && j == 4 ? 4 :
8224                         i == Xboom_bomb && j == 5 ? 2 :
8225                         i == Xboom_bomb && j == 6 ? 2 :
8226                         i == Xboom_bomb && j == 7 ? 0 :
8227                         i == Xboom_android && j == 7 ? 6 :
8228                         i == Xboom_1 && j == 1 ? 2 :
8229                         i == Xboom_1 && j == 2 ? 2 :
8230                         i == Xboom_1 && j == 3 ? 4 :
8231                         i == Xboom_1 && j == 4 ? 4 :
8232                         i == Xboom_1 && j == 5 ? 6 :
8233                         i == Xboom_1 && j == 6 ? 6 :
8234                         i == Xboom_1 && j == 7 ? 8 :
8235                         i == Xboom_2 && j == 0 ? 8 :
8236                         i == Xboom_2 && j == 1 ? 8 :
8237                         i == Xboom_2 && j == 2 ? 10 :
8238                         i == Xboom_2 && j == 3 ? 10 :
8239                         i == Xboom_2 && j == 4 ? 10 :
8240                         i == Xboom_2 && j == 5 ? 12 :
8241                         i == Xboom_2 && j == 6 ? 12 :
8242                         i == Xboom_2 && j == 7 ? 12 :
8243                         special_animation && j == 4 ? 3 :
8244                         effective_action != action ? 0 :
8245                         j);
8246
8247 #if DEBUG_EM_GFX
8248       Bitmap *debug_bitmap = g_em->bitmap;
8249       int debug_src_x = g_em->src_x;
8250       int debug_src_y = g_em->src_y;
8251 #endif
8252
8253       int frame = getAnimationFrame(g->anim_frames,
8254                                     g->anim_delay,
8255                                     g->anim_mode,
8256                                     g->anim_start_frame,
8257                                     sync_frame);
8258
8259       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8260                           g->double_movement && is_backside);
8261
8262       g_em->bitmap = src_bitmap;
8263       g_em->src_x = src_x;
8264       g_em->src_y = src_y;
8265       g_em->src_offset_x = 0;
8266       g_em->src_offset_y = 0;
8267       g_em->dst_offset_x = 0;
8268       g_em->dst_offset_y = 0;
8269       g_em->width  = TILEX;
8270       g_em->height = TILEY;
8271
8272       g_em->preserve_background = FALSE;
8273
8274 #if 1
8275       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8276                                sync_frame);
8277
8278 #else
8279
8280       g_em->crumbled_bitmap = NULL;
8281       g_em->crumbled_src_x = 0;
8282       g_em->crumbled_src_y = 0;
8283       g_em->crumbled_border_size = 0;
8284
8285       g_em->has_crumbled_graphics = FALSE;
8286
8287 #if 0
8288       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8289         printf("::: empty crumbled: %d [%s], %d, %d\n",
8290                effective_element, element_info[effective_element].token_name,
8291                effective_action, direction);
8292 #endif
8293
8294       /* if element can be crumbled, but certain action graphics are just empty
8295          space (like instantly snapping sand to empty space in 1 frame), do not
8296          treat these empty space graphics as crumbled graphics in EMC engine */
8297       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8298       {
8299         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8300                                                g_crumbled->anim_delay,
8301                                                g_crumbled->anim_mode,
8302                                                g_crumbled->anim_start_frame,
8303                                                sync_frame);
8304
8305         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8306
8307         g_em->has_crumbled_graphics = TRUE;
8308         g_em->crumbled_bitmap = src_bitmap;
8309         g_em->crumbled_src_x = src_x;
8310         g_em->crumbled_src_y = src_y;
8311         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8312
8313
8314 #if 0
8315         if (g_em == &graphic_info_em_object[207][0])
8316           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8317                  graphic_info_em_object[207][0].crumbled_src_x,
8318                  graphic_info_em_object[207][0].crumbled_src_y,
8319
8320                  crumbled, frame, src_x, src_y,
8321
8322                  g->anim_frames,
8323                  g->anim_delay,
8324                  g->anim_mode,
8325                  g->anim_start_frame,
8326                  sync_frame,
8327                  gfx.anim_random_frame,
8328                  frame);
8329 #endif
8330
8331 #if 0
8332         printf("::: EMC tile %d is crumbled\n", i);
8333 #endif
8334       }
8335 #endif
8336
8337 #if 0
8338       if (element == EL_ROCK &&
8339           effective_action == ACTION_FILLING)
8340         printf("::: has_action_graphics == %d\n", has_action_graphics);
8341 #endif
8342
8343       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8344                                    effective_action == ACTION_MOVING  ||
8345                                    effective_action == ACTION_PUSHING ||
8346                                    effective_action == ACTION_EATING)) ||
8347           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8348                                     effective_action == ACTION_EMPTYING)))
8349       {
8350         int move_dir =
8351           (effective_action == ACTION_FALLING ||
8352            effective_action == ACTION_FILLING ||
8353            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8354         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8355         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8356         int num_steps = (i == Ydrip_s1  ? 16 :
8357                          i == Ydrip_s1B ? 16 :
8358                          i == Ydrip_s2  ? 16 :
8359                          i == Ydrip_s2B ? 16 :
8360                          i == Xsand_stonein_1 ? 32 :
8361                          i == Xsand_stonein_2 ? 32 :
8362                          i == Xsand_stonein_3 ? 32 :
8363                          i == Xsand_stonein_4 ? 32 :
8364                          i == Xsand_stoneout_1 ? 16 :
8365                          i == Xsand_stoneout_2 ? 16 : 8);
8366         int cx = ABS(dx) * (TILEX / num_steps);
8367         int cy = ABS(dy) * (TILEY / num_steps);
8368         int step_frame = (i == Ydrip_s2         ? j + 8 :
8369                           i == Ydrip_s2B        ? j + 8 :
8370                           i == Xsand_stonein_2  ? j + 8 :
8371                           i == Xsand_stonein_3  ? j + 16 :
8372                           i == Xsand_stonein_4  ? j + 24 :
8373                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8374         int step = (is_backside ? step_frame : num_steps - step_frame);
8375
8376         if (is_backside)        /* tile where movement starts */
8377         {
8378           if (dx < 0 || dy < 0)
8379           {
8380             g_em->src_offset_x = cx * step;
8381             g_em->src_offset_y = cy * step;
8382           }
8383           else
8384           {
8385             g_em->dst_offset_x = cx * step;
8386             g_em->dst_offset_y = cy * step;
8387           }
8388         }
8389         else                    /* tile where movement ends */
8390         {
8391           if (dx < 0 || dy < 0)
8392           {
8393             g_em->dst_offset_x = cx * step;
8394             g_em->dst_offset_y = cy * step;
8395           }
8396           else
8397           {
8398             g_em->src_offset_x = cx * step;
8399             g_em->src_offset_y = cy * step;
8400           }
8401         }
8402
8403         g_em->width  = TILEX - cx * step;
8404         g_em->height = TILEY - cy * step;
8405       }
8406
8407       /* create unique graphic identifier to decide if tile must be redrawn */
8408       /* bit 31 - 16 (16 bit): EM style graphic
8409          bit 15 - 12 ( 4 bit): EM style frame
8410          bit 11 -  6 ( 6 bit): graphic width
8411          bit  5 -  0 ( 6 bit): graphic height */
8412       g_em->unique_identifier =
8413         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8414
8415 #if DEBUG_EM_GFX
8416
8417       /* skip check for EMC elements not contained in original EMC artwork */
8418       if (element == EL_EMC_FAKE_ACID)
8419         continue;
8420
8421       if (g_em->bitmap != debug_bitmap ||
8422           g_em->src_x != debug_src_x ||
8423           g_em->src_y != debug_src_y ||
8424           g_em->src_offset_x != 0 ||
8425           g_em->src_offset_y != 0 ||
8426           g_em->dst_offset_x != 0 ||
8427           g_em->dst_offset_y != 0 ||
8428           g_em->width != TILEX ||
8429           g_em->height != TILEY)
8430       {
8431         static int last_i = -1;
8432
8433         if (i != last_i)
8434         {
8435           printf("\n");
8436           last_i = i;
8437         }
8438
8439         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8440                i, element, element_info[element].token_name,
8441                element_action_info[effective_action].suffix, direction);
8442
8443         if (element != effective_element)
8444           printf(" [%d ('%s')]",
8445                  effective_element,
8446                  element_info[effective_element].token_name);
8447
8448         printf("\n");
8449
8450         if (g_em->bitmap != debug_bitmap)
8451           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8452                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8453
8454         if (g_em->src_x != debug_src_x ||
8455             g_em->src_y != debug_src_y)
8456           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8457                  j, (is_backside ? 'B' : 'F'),
8458                  g_em->src_x, g_em->src_y,
8459                  g_em->src_x / 32, g_em->src_y / 32,
8460                  debug_src_x, debug_src_y,
8461                  debug_src_x / 32, debug_src_y / 32);
8462
8463         if (g_em->src_offset_x != 0 ||
8464             g_em->src_offset_y != 0 ||
8465             g_em->dst_offset_x != 0 ||
8466             g_em->dst_offset_y != 0)
8467           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8468                  j, is_backside,
8469                  g_em->src_offset_x, g_em->src_offset_y,
8470                  g_em->dst_offset_x, g_em->dst_offset_y);
8471
8472         if (g_em->width != TILEX ||
8473             g_em->height != TILEY)
8474           printf("    %d (%d): size %d,%d should be %d,%d\n",
8475                  j, is_backside,
8476                  g_em->width, g_em->height, TILEX, TILEY);
8477
8478         num_em_gfx_errors++;
8479       }
8480 #endif
8481
8482     }
8483   }
8484
8485   for (i = 0; i < TILE_MAX; i++)
8486   {
8487     for (j = 0; j < 8; j++)
8488     {
8489       int element = object_mapping[i].element_rnd;
8490       int action = object_mapping[i].action;
8491       int direction = object_mapping[i].direction;
8492       boolean is_backside = object_mapping[i].is_backside;
8493       int graphic_action  = el_act_dir2img(element, action, direction);
8494       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8495
8496       if ((action == ACTION_SMASHED_BY_ROCK ||
8497            action == ACTION_SMASHED_BY_SPRING ||
8498            action == ACTION_EATING) &&
8499           graphic_action == graphic_default)
8500       {
8501         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
8502                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8503                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
8504                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8505                  Xspring);
8506
8507         /* no separate animation for "smashed by rock" -- use rock instead */
8508         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8509         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8510
8511         g_em->bitmap            = g_xx->bitmap;
8512         g_em->src_x             = g_xx->src_x;
8513         g_em->src_y             = g_xx->src_y;
8514         g_em->src_offset_x      = g_xx->src_offset_x;
8515         g_em->src_offset_y      = g_xx->src_offset_y;
8516         g_em->dst_offset_x      = g_xx->dst_offset_x;
8517         g_em->dst_offset_y      = g_xx->dst_offset_y;
8518         g_em->width             = g_xx->width;
8519         g_em->height            = g_xx->height;
8520         g_em->unique_identifier = g_xx->unique_identifier;
8521
8522         if (!is_backside)
8523           g_em->preserve_background = TRUE;
8524       }
8525     }
8526   }
8527
8528   for (p = 0; p < MAX_PLAYERS; p++)
8529   {
8530     for (i = 0; i < SPR_MAX; i++)
8531     {
8532       int element = player_mapping[p][i].element_rnd;
8533       int action = player_mapping[p][i].action;
8534       int direction = player_mapping[p][i].direction;
8535
8536       for (j = 0; j < 8; j++)
8537       {
8538         int effective_element = element;
8539         int effective_action = action;
8540         int graphic = (direction == MV_NONE ?
8541                        el_act2img(effective_element, effective_action) :
8542                        el_act_dir2img(effective_element, effective_action,
8543                                       direction));
8544         struct GraphicInfo *g = &graphic_info[graphic];
8545         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8546         Bitmap *src_bitmap;
8547         int src_x, src_y;
8548         int sync_frame = j;
8549
8550 #if DEBUG_EM_GFX
8551         Bitmap *debug_bitmap = g_em->bitmap;
8552         int debug_src_x = g_em->src_x;
8553         int debug_src_y = g_em->src_y;
8554 #endif
8555
8556         int frame = getAnimationFrame(g->anim_frames,
8557                                       g->anim_delay,
8558                                       g->anim_mode,
8559                                       g->anim_start_frame,
8560                                       sync_frame);
8561
8562         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8563
8564         g_em->bitmap = src_bitmap;
8565         g_em->src_x = src_x;
8566         g_em->src_y = src_y;
8567         g_em->src_offset_x = 0;
8568         g_em->src_offset_y = 0;
8569         g_em->dst_offset_x = 0;
8570         g_em->dst_offset_y = 0;
8571         g_em->width  = TILEX;
8572         g_em->height = TILEY;
8573
8574 #if DEBUG_EM_GFX
8575
8576         /* skip check for EMC elements not contained in original EMC artwork */
8577         if (element == EL_PLAYER_3 ||
8578             element == EL_PLAYER_4)
8579           continue;
8580
8581         if (g_em->bitmap != debug_bitmap ||
8582             g_em->src_x != debug_src_x ||
8583             g_em->src_y != debug_src_y)
8584         {
8585           static int last_i = -1;
8586
8587           if (i != last_i)
8588           {
8589             printf("\n");
8590             last_i = i;
8591           }
8592
8593           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8594                  p, i, element, element_info[element].token_name,
8595                  element_action_info[effective_action].suffix, direction);
8596
8597           if (element != effective_element)
8598             printf(" [%d ('%s')]",
8599                    effective_element,
8600                    element_info[effective_element].token_name);
8601
8602           printf("\n");
8603
8604           if (g_em->bitmap != debug_bitmap)
8605             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
8606                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
8607
8608           if (g_em->src_x != debug_src_x ||
8609               g_em->src_y != debug_src_y)
8610             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8611                    j,
8612                    g_em->src_x, g_em->src_y,
8613                    g_em->src_x / 32, g_em->src_y / 32,
8614                    debug_src_x, debug_src_y,
8615                    debug_src_x / 32, debug_src_y / 32);
8616
8617           num_em_gfx_errors++;
8618         }
8619 #endif
8620
8621       }
8622     }
8623   }
8624
8625 #if DEBUG_EM_GFX
8626   printf("\n");
8627   printf("::: [%d errors found]\n", num_em_gfx_errors);
8628
8629   exit(0);
8630 #endif
8631 }
8632
8633 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8634                             boolean any_player_moving,
8635                             boolean player_is_dropping)
8636 {
8637   int i;
8638
8639   if (tape.single_step && tape.recording && !tape.pausing)
8640   {
8641     boolean active_players = FALSE;
8642
8643     for (i = 0; i < MAX_PLAYERS; i++)
8644       if (action[i] != JOY_NO_ACTION)
8645         active_players = TRUE;
8646
8647     // if (frame == 0)
8648     if (frame == 0 && !player_is_dropping)
8649       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8650   }
8651 }
8652
8653 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8654                             boolean murphy_is_dropping)
8655 {
8656 #if 0
8657   printf("::: waiting: %d, dropping: %d\n",
8658          murphy_is_waiting, murphy_is_dropping);
8659 #endif
8660
8661   if (tape.single_step && tape.recording && !tape.pausing)
8662   {
8663     // if (murphy_is_waiting || murphy_is_dropping)
8664     if (murphy_is_waiting)
8665     {
8666 #if 0
8667       printf("::: murphy is waiting -> pause mode\n");
8668 #endif
8669
8670       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8671     }
8672   }
8673 }
8674
8675 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8676                          int graphic, int sync_frame, int x, int y)
8677 {
8678   int frame = getGraphicAnimationFrame(graphic, sync_frame);
8679
8680   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8681 }
8682
8683 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8684 {
8685   return (IS_NEXT_FRAME(sync_frame, graphic));
8686 }
8687
8688 int getGraphicInfo_Delay(int graphic)
8689 {
8690   return graphic_info[graphic].anim_delay;
8691 }
8692
8693 void PlayMenuSoundExt(int sound)
8694 {
8695   if (sound == SND_UNDEFINED)
8696     return;
8697
8698   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8699       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8700     return;
8701
8702   if (IS_LOOP_SOUND(sound))
8703     PlaySoundLoop(sound);
8704   else
8705     PlaySound(sound);
8706 }
8707
8708 void PlayMenuSound()
8709 {
8710   PlayMenuSoundExt(menu.sound[game_status]);
8711 }
8712
8713 void PlayMenuSoundStereo(int sound, int stereo_position)
8714 {
8715   if (sound == SND_UNDEFINED)
8716     return;
8717
8718   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8719       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8720     return;
8721
8722   if (IS_LOOP_SOUND(sound))
8723     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8724   else
8725     PlaySoundStereo(sound, stereo_position);
8726 }
8727
8728 void PlayMenuSoundIfLoopExt(int sound)
8729 {
8730   if (sound == SND_UNDEFINED)
8731     return;
8732
8733   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8734       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8735     return;
8736
8737   if (IS_LOOP_SOUND(sound))
8738     PlaySoundLoop(sound);
8739 }
8740
8741 void PlayMenuSoundIfLoop()
8742 {
8743   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8744 }
8745
8746 void PlayMenuMusicExt(int music)
8747 {
8748   if (music == MUS_UNDEFINED)
8749     return;
8750
8751   if (!setup.sound_music)
8752     return;
8753
8754   PlayMusic(music);
8755 }
8756
8757 void PlayMenuMusic()
8758 {
8759   PlayMenuMusicExt(menu.music[game_status]);
8760 }
8761
8762 void PlaySoundActivating()
8763 {
8764 #if 0
8765   PlaySound(SND_MENU_ITEM_ACTIVATING);
8766 #endif
8767 }
8768
8769 void PlaySoundSelecting()
8770 {
8771 #if 0
8772   PlaySound(SND_MENU_ITEM_SELECTING);
8773 #endif
8774 }
8775
8776 void ToggleFullscreenIfNeeded()
8777 {
8778   boolean change_fullscreen = (setup.fullscreen !=
8779                                video.fullscreen_enabled);
8780   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8781                                     !strEqual(setup.fullscreen_mode,
8782                                               video.fullscreen_mode_current));
8783
8784   if (!video.fullscreen_available)
8785     return;
8786
8787   if (change_fullscreen || change_fullscreen_mode)
8788   {
8789     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8790
8791     /* save backbuffer content which gets lost when toggling fullscreen mode */
8792     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8793
8794     if (change_fullscreen_mode)
8795     {
8796       /* keep fullscreen, but change fullscreen mode (screen resolution) */
8797       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
8798     }
8799
8800     /* toggle fullscreen */
8801     ChangeVideoModeIfNeeded(setup.fullscreen);
8802
8803     setup.fullscreen = video.fullscreen_enabled;
8804
8805     /* restore backbuffer content from temporary backbuffer backup bitmap */
8806     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8807
8808     FreeBitmap(tmp_backbuffer);
8809
8810 #if 1
8811     /* update visible window/screen */
8812     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8813 #else
8814     redraw_mask = REDRAW_ALL;
8815 #endif
8816   }
8817 }
8818
8819 void ChangeViewportPropertiesIfNeeded()
8820 {
8821   int *door_1_x = &DX;
8822   int *door_1_y = &DY;
8823   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8824   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8825   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8826                        game_status == GAME_MODE_EDITOR ? game_status :
8827                        GAME_MODE_MAIN);
8828   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8829   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8830   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8831   int border_size = vp_playfield->border_size;
8832   int new_sx = vp_playfield->x + border_size;
8833   int new_sy = vp_playfield->y + border_size;
8834   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? TILESIZE_VAR :
8835                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8836   int new_sxsize = vp_playfield->width  - 2 * border_size;
8837   int new_sysize = vp_playfield->height - 2 * border_size;
8838 #if NEW_TILESIZE
8839   int new_scr_fieldx = new_sxsize / tilesize;
8840   int new_scr_fieldy = new_sysize / tilesize;
8841 #else
8842   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
8843   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8844 #endif
8845
8846 #if 0
8847   /* !!! TEST ONLY !!! */
8848   // InitGfxBuffers();
8849   return;
8850 #endif
8851
8852   if (viewport.window.width  != WIN_XSIZE ||
8853       viewport.window.height != WIN_YSIZE)
8854   {
8855     WIN_XSIZE = viewport.window.width;
8856     WIN_YSIZE = viewport.window.height;
8857
8858     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8859     InitGfxBuffers();
8860
8861 #if 1
8862     SetDrawDeactivationMask(REDRAW_NONE);
8863     SetDrawBackgroundMask(REDRAW_FIELD);
8864
8865     // RedrawBackground();
8866 #endif
8867   }
8868
8869   if (new_scr_fieldx != SCR_FIELDX ||
8870       new_scr_fieldy != SCR_FIELDY ||
8871       new_sx != SX ||
8872       new_sy != SY ||
8873       vp_playfield->x != REAL_SX ||
8874       vp_playfield->y != REAL_SY ||
8875       vp_door_1->x != *door_1_x ||
8876       vp_door_1->y != *door_1_y ||
8877       vp_door_2->x != *door_2_x ||
8878       vp_door_2->y != *door_2_y)
8879   {
8880     SCR_FIELDX = new_scr_fieldx;
8881     SCR_FIELDY = new_scr_fieldy;
8882     SX = new_sx;
8883     SY = new_sy;
8884     REAL_SX = vp_playfield->x;
8885     REAL_SY = vp_playfield->y;
8886
8887     SXSIZE = new_sxsize;
8888     SYSIZE = new_sysize;
8889     FULL_SXSIZE = vp_playfield->width;
8890     FULL_SYSIZE = vp_playfield->width;
8891
8892     *door_1_x = vp_door_1->x;
8893     *door_1_y = vp_door_1->y;
8894     *door_2_x = vp_door_2->x;
8895     *door_2_y = vp_door_2->y;
8896
8897     InitGfxBuffers();
8898
8899     if (gfx_game_mode == GAME_MODE_MAIN)
8900     {
8901       InitGadgets();
8902       InitToons();
8903     }
8904   }
8905
8906 #if 0
8907   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
8908 #endif
8909 }