rnd-20100624-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "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   global.use_envelope_request = TRUE  * 1;
3667
3668 #if 1
3669   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3670   {
3671     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3672     font_nr = FONT_TEXT_1;
3673   }
3674 #else
3675   for (text_ptr = text; *text_ptr; text_ptr++)
3676   {
3677     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3678
3679     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3680     {
3681       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3682 #if 1
3683       font_nr = FONT_TEXT_1;
3684 #else
3685       font_nr = FONT_LEVEL_NUMBER;
3686 #endif
3687
3688       break;
3689     }
3690   }
3691 #endif
3692
3693   if (game_status == GAME_MODE_PLAYING)
3694   {
3695     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3696       BlitScreenToBitmap_EM(backbuffer);
3697     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3698       BlitScreenToBitmap_SP(backbuffer);
3699   }
3700
3701   /* disable deactivated drawing when quick-loading level tape recording */
3702   if (tape.playing && tape.deactivate_display)
3703     TapeDeactivateDisplayOff(TRUE);
3704
3705   SetMouseCursor(CURSOR_DEFAULT);
3706
3707 #if defined(NETWORK_AVALIABLE)
3708   /* pause network game while waiting for request to answer */
3709   if (options.network &&
3710       game_status == GAME_MODE_PLAYING &&
3711       req_state & REQUEST_WAIT_FOR_INPUT)
3712     SendToServer_PausePlaying();
3713 #endif
3714
3715   old_door_state = GetDoorState();
3716
3717   /* simulate releasing mouse button over last gadget, if still pressed */
3718   if (button_status)
3719     HandleGadgets(-1, -1, 0);
3720
3721   UnmapAllGadgets();
3722
3723   /* draw released gadget before proceeding */
3724   // BackToFront();
3725
3726 #if 0
3727   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3728 #else
3729   if (old_door_state & DOOR_OPEN_1)
3730 #endif
3731   {
3732 #if 1
3733     if (!global.use_envelope_request)
3734       CloseDoor(DOOR_CLOSE_1);
3735 #else
3736     CloseDoor(DOOR_CLOSE_1);
3737 #endif
3738
3739     /* save old door content */
3740     BlitBitmap(bitmap_db_door, bitmap_db_door,
3741                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3742                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3743   }
3744
3745 #if 1
3746   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3747 #endif
3748
3749   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3750
3751   /* clear door drawing field */
3752   DrawBackground(DX, DY, DXSIZE, DYSIZE);
3753
3754   /* force DOOR font inside door area */
3755   game_status = GAME_MODE_PSEUDO_DOOR;
3756
3757   /* write text for request */
3758   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3759   {
3760     char text_line[max_request_line_len + 1];
3761     int tx, tl, tc = 0;
3762
3763     if (!*text_ptr)
3764       break;
3765
3766     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3767     {
3768       tc = *(text_ptr + tx);
3769       if (!tc || tc == ' ')
3770         break;
3771     }
3772
3773     if (!tl)
3774     { 
3775       text_ptr++; 
3776       ty--; 
3777       continue; 
3778     }
3779
3780     strncpy(text_line, text_ptr, tl);
3781     text_line[tl] = 0;
3782
3783     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3784              DY + 8 + ty * (getFontHeight(font_nr) + 2),
3785              text_line, font_nr);
3786
3787     text_ptr += tl + (tc == ' ' ? 1 : 0);
3788   }
3789
3790   game_status = last_game_status;       /* restore current game status */
3791
3792 #if 1
3793   if (global.use_envelope_request)
3794   {
3795     /* !!! TMP !!! */
3796     FreeToolButtons();
3797     CreateToolButtons();
3798   }
3799 #endif
3800
3801   if (req_state & REQ_ASK)
3802   {
3803     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3804     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3805   }
3806   else if (req_state & REQ_CONFIRM)
3807   {
3808     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3809   }
3810   else if (req_state & REQ_PLAYER)
3811   {
3812     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3813     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3814     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3815     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3816   }
3817
3818   /* copy request gadgets to door backbuffer */
3819   BlitBitmap(drawto, bitmap_db_door,
3820              DX, DY, DXSIZE, DYSIZE,
3821              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3822
3823 #if 1
3824   if (global.use_envelope_request)
3825   {
3826     ShowEnvelopeDoor(text, ACTION_OPENING);
3827
3828     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3829     {
3830       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
3831                                    i == TOOL_CTRL_ID_NO)) ||
3832           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
3833           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
3834                                       i == TOOL_CTRL_ID_PLAYER_2 &&
3835                                       i == TOOL_CTRL_ID_PLAYER_3 &&
3836                                       i == TOOL_CTRL_ID_PLAYER_4)))
3837       {
3838         int x = tool_gadget[i]->x + dDX;
3839         int y = tool_gadget[i]->y + dDY;
3840
3841         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
3842       }
3843     }
3844   }
3845 #endif
3846
3847 #if 1
3848   if (!global.use_envelope_request)
3849     OpenDoor(DOOR_OPEN_1);
3850 #else
3851   OpenDoor(DOOR_OPEN_1);
3852 #endif
3853
3854   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3855   {
3856     if (game_status == GAME_MODE_PLAYING)
3857     {
3858       SetPanelBackground();
3859       SetDrawBackgroundMask(REDRAW_DOOR_1);
3860     }
3861     else
3862     {
3863       SetDrawBackgroundMask(REDRAW_FIELD);
3864     }
3865
3866     return FALSE;
3867   }
3868
3869 #if 1
3870   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
3871     InitAnimation();
3872 #else
3873   if (game_status != GAME_MODE_MAIN)
3874     InitAnimation();
3875 #endif
3876
3877   button_status = MB_RELEASED;
3878
3879   request_gadget_id = -1;
3880
3881   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3882
3883   while (result < 0)
3884   {
3885     if (PendingEvent())
3886     {
3887       Event event;
3888
3889       NextEvent(&event);
3890
3891       switch (event.type)
3892       {
3893         case EVENT_BUTTONPRESS:
3894         case EVENT_BUTTONRELEASE:
3895         case EVENT_MOTIONNOTIFY:
3896         {
3897           if (event.type == EVENT_MOTIONNOTIFY)
3898           {
3899             if (!PointerInWindow(window))
3900               continue; /* window and pointer are on different screens */
3901
3902             if (!button_status)
3903               continue;
3904
3905             motion_status = TRUE;
3906             mx = ((MotionEvent *) &event)->x;
3907             my = ((MotionEvent *) &event)->y;
3908           }
3909           else
3910           {
3911             motion_status = FALSE;
3912             mx = ((ButtonEvent *) &event)->x;
3913             my = ((ButtonEvent *) &event)->y;
3914             if (event.type == EVENT_BUTTONPRESS)
3915               button_status = ((ButtonEvent *) &event)->button;
3916             else
3917               button_status = MB_RELEASED;
3918           }
3919
3920           /* this sets 'request_gadget_id' */
3921           HandleGadgets(mx, my, button_status);
3922
3923           switch (request_gadget_id)
3924           {
3925             case TOOL_CTRL_ID_YES:
3926               result = TRUE;
3927               break;
3928             case TOOL_CTRL_ID_NO:
3929               result = FALSE;
3930               break;
3931             case TOOL_CTRL_ID_CONFIRM:
3932               result = TRUE | FALSE;
3933               break;
3934
3935             case TOOL_CTRL_ID_PLAYER_1:
3936               result = 1;
3937               break;
3938             case TOOL_CTRL_ID_PLAYER_2:
3939               result = 2;
3940               break;
3941             case TOOL_CTRL_ID_PLAYER_3:
3942               result = 3;
3943               break;
3944             case TOOL_CTRL_ID_PLAYER_4:
3945               result = 4;
3946               break;
3947
3948             default:
3949               break;
3950           }
3951
3952           break;
3953         }
3954
3955         case EVENT_KEYPRESS:
3956           switch (GetEventKey((KeyEvent *)&event, TRUE))
3957           {
3958             case KSYM_space:
3959               if (req_state & REQ_CONFIRM)
3960                 result = 1;
3961               break;
3962
3963             case KSYM_Return:
3964               result = 1;
3965               break;
3966
3967             case KSYM_Escape:
3968               result = 0;
3969               break;
3970
3971             default:
3972               break;
3973           }
3974
3975           if (req_state & REQ_PLAYER)
3976             result = 0;
3977           break;
3978
3979         case EVENT_KEYRELEASE:
3980           ClearPlayerAction();
3981           break;
3982
3983         default:
3984           HandleOtherEvents(&event);
3985           break;
3986       }
3987     }
3988     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3989     {
3990       int joy = AnyJoystick();
3991
3992       if (joy & JOY_BUTTON_1)
3993         result = 1;
3994       else if (joy & JOY_BUTTON_2)
3995         result = 0;
3996     }
3997
3998 #if 1
3999
4000     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4001     {
4002       HandleGameActions();
4003     }
4004     else
4005     {
4006       DoAnimation();
4007
4008       if (!PendingEvent())      /* delay only if no pending events */
4009         Delay(10);
4010     }
4011
4012 #if 1
4013     game_status = GAME_MODE_PSEUDO_DOOR;
4014 #endif
4015
4016     BackToFront();
4017
4018 #if 1
4019     game_status = last_game_status;     /* restore current game status */
4020 #endif
4021
4022 #else
4023
4024     DoAnimation();
4025
4026 #if 1
4027     if (!PendingEvent())        /* delay only if no pending events */
4028       Delay(10);
4029 #else
4030     /* don't eat all CPU time */
4031     Delay(10);
4032 #endif
4033
4034 #endif
4035   }
4036
4037   if (game_status != GAME_MODE_MAIN)
4038     StopAnimation();
4039
4040   UnmapToolButtons();
4041
4042 #if 1
4043   if (global.use_envelope_request)
4044     ShowEnvelopeDoor(text, ACTION_CLOSING);
4045 #endif
4046
4047 #if 1
4048   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4049 #else
4050   if (!(req_state & REQ_STAY_OPEN))
4051 #endif
4052   {
4053     CloseDoor(DOOR_CLOSE_1);
4054
4055     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4056         (req_state & REQ_REOPEN))
4057       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4058   }
4059
4060   RemapAllGadgets();
4061
4062   if (game_status == GAME_MODE_PLAYING)
4063   {
4064     SetPanelBackground();
4065     SetDrawBackgroundMask(REDRAW_DOOR_1);
4066   }
4067   else
4068   {
4069     SetDrawBackgroundMask(REDRAW_FIELD);
4070   }
4071
4072 #if defined(NETWORK_AVALIABLE)
4073   /* continue network game after request */
4074   if (options.network &&
4075       game_status == GAME_MODE_PLAYING &&
4076       req_state & REQUEST_WAIT_FOR_INPUT)
4077     SendToServer_ContinuePlaying();
4078 #endif
4079
4080   /* restore deactivated drawing when quick-loading level tape recording */
4081   if (tape.playing && tape.deactivate_display)
4082     TapeDeactivateDisplayOn();
4083
4084   return result;
4085 }
4086
4087 unsigned int OpenDoor(unsigned int door_state)
4088 {
4089   if (door_state & DOOR_COPY_BACK)
4090   {
4091     if (door_state & DOOR_OPEN_1)
4092       BlitBitmap(bitmap_db_door, bitmap_db_door,
4093                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4094                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4095
4096     if (door_state & DOOR_OPEN_2)
4097       BlitBitmap(bitmap_db_door, bitmap_db_door,
4098                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4099                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4100
4101     door_state &= ~DOOR_COPY_BACK;
4102   }
4103
4104   return MoveDoor(door_state);
4105 }
4106
4107 unsigned int CloseDoor(unsigned int door_state)
4108 {
4109   unsigned int old_door_state = GetDoorState();
4110
4111   if (!(door_state & DOOR_NO_COPY_BACK))
4112   {
4113     if (old_door_state & DOOR_OPEN_1)
4114       BlitBitmap(backbuffer, bitmap_db_door,
4115                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4116
4117     if (old_door_state & DOOR_OPEN_2)
4118       BlitBitmap(backbuffer, bitmap_db_door,
4119                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4120
4121     door_state &= ~DOOR_NO_COPY_BACK;
4122   }
4123
4124   return MoveDoor(door_state);
4125 }
4126
4127 unsigned int GetDoorState()
4128 {
4129   return MoveDoor(DOOR_GET_STATE);
4130 }
4131
4132 unsigned int SetDoorState(unsigned int door_state)
4133 {
4134   return MoveDoor(door_state | DOOR_SET_STATE);
4135 }
4136
4137 unsigned int MoveDoor(unsigned int door_state)
4138 {
4139   static int door1 = DOOR_OPEN_1;
4140   static int door2 = DOOR_CLOSE_2;
4141   unsigned long door_delay = 0;
4142   unsigned long door_delay_value;
4143   int stepsize = 1;
4144
4145   if (door_1.width < 0 || door_1.width > DXSIZE)
4146     door_1.width = DXSIZE;
4147   if (door_1.height < 0 || door_1.height > DYSIZE)
4148     door_1.height = DYSIZE;
4149   if (door_2.width < 0 || door_2.width > VXSIZE)
4150     door_2.width = VXSIZE;
4151   if (door_2.height < 0 || door_2.height > VYSIZE)
4152     door_2.height = VYSIZE;
4153
4154   if (door_state == DOOR_GET_STATE)
4155     return (door1 | door2);
4156
4157   if (door_state & DOOR_SET_STATE)
4158   {
4159     if (door_state & DOOR_ACTION_1)
4160       door1 = door_state & DOOR_ACTION_1;
4161     if (door_state & DOOR_ACTION_2)
4162       door2 = door_state & DOOR_ACTION_2;
4163
4164     return (door1 | door2);
4165   }
4166
4167   if (!(door_state & DOOR_FORCE_REDRAW))
4168   {
4169     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4170       door_state &= ~DOOR_OPEN_1;
4171     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4172       door_state &= ~DOOR_CLOSE_1;
4173     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4174       door_state &= ~DOOR_OPEN_2;
4175     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4176       door_state &= ~DOOR_CLOSE_2;
4177   }
4178
4179   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4180                       door_2.step_delay);
4181
4182   if (setup.quick_doors)
4183   {
4184     stepsize = 20;              /* must be chosen to always draw last frame */
4185     door_delay_value = 0;
4186   }
4187
4188   if (global.autoplay_leveldir)
4189   {
4190     door_state |= DOOR_NO_DELAY;
4191     door_state &= ~DOOR_CLOSE_ALL;
4192   }
4193
4194 #if 1
4195   if (game_status == GAME_MODE_EDITOR)
4196     door_state |= DOOR_NO_DELAY;
4197 #endif
4198
4199   if (door_state & DOOR_ACTION)
4200   {
4201     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4202     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4203     boolean door_1_done = (!handle_door_1);
4204     boolean door_2_done = (!handle_door_2);
4205     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4206     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4207     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4208     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4209     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4210     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4211     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
4212     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4213     int door_skip = max_door_size - door_size;
4214     int end = door_size;
4215     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4216     int k;
4217
4218     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4219     {
4220       /* opening door sound has priority over simultaneously closing door */
4221       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4222         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4223       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4224         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4225     }
4226
4227     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4228     {
4229       int x = k;
4230       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4231       GC gc = bitmap->stored_clip_gc;
4232
4233       if (door_state & DOOR_ACTION_1)
4234       {
4235         int a = MIN(x * door_1.step_offset, end);
4236         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4237         int i = p + door_skip;
4238
4239         if (door_1.anim_mode & ANIM_STATIC_PANEL)
4240         {
4241           BlitBitmap(bitmap_db_door, drawto,
4242                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4243                      DXSIZE, DYSIZE, DX, DY);
4244         }
4245         else if (x <= a)
4246         {
4247           BlitBitmap(bitmap_db_door, drawto,
4248                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4249                      DXSIZE, DYSIZE - p / 2, DX, DY);
4250
4251           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4252         }
4253
4254         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4255         {
4256           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4257           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4258           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
4259           int dst2_x = DX,              dst2_y = DY;
4260           int width = i, height = DYSIZE;
4261
4262           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4263           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4264                            dst1_x, dst1_y);
4265
4266           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4267           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4268                            dst2_x, dst2_y);
4269         }
4270         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4271         {
4272           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4273           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
4274           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4275           int dst2_x = DX,              dst2_y = DY;
4276           int width = DXSIZE, height = i;
4277
4278           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4279           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4280                            dst1_x, dst1_y);
4281
4282           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4283           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4284                            dst2_x, dst2_y);
4285         }
4286         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
4287         {
4288           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4289
4290           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4291           BlitBitmapMasked(bitmap, drawto,
4292                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4293                            DX + DXSIZE - i, DY + j);
4294           BlitBitmapMasked(bitmap, drawto,
4295                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4296                            DX + DXSIZE - i, DY + 140 + j);
4297           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4298                         DY - (DOOR_GFX_PAGEY1 + j));
4299           BlitBitmapMasked(bitmap, drawto,
4300                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4301                            DX, DY);
4302           BlitBitmapMasked(bitmap, drawto,
4303                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4304                            DX, DY + 140 - j);
4305
4306           BlitBitmapMasked(bitmap, drawto,
4307                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4308                            DX, DY + 77 - j);
4309           BlitBitmapMasked(bitmap, drawto,
4310                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4311                            DX, DY + 203 - j);
4312           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4313           BlitBitmapMasked(bitmap, drawto,
4314                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4315                            DX + DXSIZE - i, DY + 77 + j);
4316           BlitBitmapMasked(bitmap, drawto,
4317                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4318                            DX + DXSIZE - i, DY + 203 + j);
4319         }
4320
4321         redraw_mask |= REDRAW_DOOR_1;
4322         door_1_done = (a == end);
4323       }
4324
4325       if (door_state & DOOR_ACTION_2)
4326       {
4327         int a = MIN(x * door_2.step_offset, door_size);
4328         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4329         int i = p + door_skip;
4330
4331         if (door_2.anim_mode & ANIM_STATIC_PANEL)
4332         {
4333           BlitBitmap(bitmap_db_door, drawto,
4334                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4335                      VXSIZE, VYSIZE, VX, VY);
4336         }
4337         else if (x <= VYSIZE)
4338         {
4339           BlitBitmap(bitmap_db_door, drawto,
4340                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4341                      VXSIZE, VYSIZE - p / 2, VX, VY);
4342
4343           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4344         }
4345
4346         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4347         {
4348           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4349           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4350           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
4351           int dst2_x = VX,              dst2_y = VY;
4352           int width = i, height = VYSIZE;
4353
4354           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4355           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4356                            dst1_x, dst1_y);
4357
4358           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4359           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4360                            dst2_x, dst2_y);
4361         }
4362         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4363         {
4364           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4365           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
4366           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4367           int dst2_x = VX,              dst2_y = VY;
4368           int width = VXSIZE, height = i;
4369
4370           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4371           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4372                            dst1_x, dst1_y);
4373
4374           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4375           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4376                            dst2_x, dst2_y);
4377         }
4378         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
4379         {
4380           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4381
4382           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4383           BlitBitmapMasked(bitmap, drawto,
4384                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4385                            VX + VXSIZE - i, VY + j);
4386           SetClipOrigin(bitmap, gc,
4387                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4388           BlitBitmapMasked(bitmap, drawto,
4389                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4390                            VX, VY);
4391
4392           BlitBitmapMasked(bitmap, drawto,
4393                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4394                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4395           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4396           BlitBitmapMasked(bitmap, drawto,
4397                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4398                            i, VYSIZE / 2 - j,
4399                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4400         }
4401
4402         redraw_mask |= REDRAW_DOOR_2;
4403         door_2_done = (a == VXSIZE);
4404       }
4405
4406       if (!(door_state & DOOR_NO_DELAY))
4407       {
4408         BackToFront();
4409
4410         if (game_status == GAME_MODE_MAIN)
4411           DoAnimation();
4412
4413         WaitUntilDelayReached(&door_delay, door_delay_value);
4414       }
4415     }
4416   }
4417
4418   if (door_state & DOOR_ACTION_1)
4419     door1 = door_state & DOOR_ACTION_1;
4420   if (door_state & DOOR_ACTION_2)
4421     door2 = door_state & DOOR_ACTION_2;
4422
4423   return (door1 | door2);
4424 }
4425
4426 void DrawSpecialEditorDoor()
4427 {
4428   /* draw bigger toolbox window */
4429   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4430              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4431              EX - 4, EY - 12);
4432   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4433              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4434              EX - 6, EY - 4);
4435
4436   redraw_mask |= REDRAW_ALL;
4437 }
4438
4439 void UndrawSpecialEditorDoor()
4440 {
4441   /* draw normal tape recorder window */
4442   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4443              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4444              EX - 6, EY - 12);
4445
4446   redraw_mask |= REDRAW_ALL;
4447 }
4448
4449
4450 /* ---------- new tool button stuff ---------------------------------------- */
4451
4452 /* graphic position values for tool buttons */
4453 #define TOOL_BUTTON_YES_XPOS            2
4454 #define TOOL_BUTTON_YES_YPOS            250
4455 #define TOOL_BUTTON_YES_GFX_YPOS        0
4456 #define TOOL_BUTTON_YES_XSIZE           46
4457 #define TOOL_BUTTON_YES_YSIZE           28
4458 #define TOOL_BUTTON_NO_XPOS             52
4459 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
4460 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
4461 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
4462 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
4463 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
4464 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
4465 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
4466 #define TOOL_BUTTON_CONFIRM_XSIZE       96
4467 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
4468 #define TOOL_BUTTON_PLAYER_XSIZE        30
4469 #define TOOL_BUTTON_PLAYER_YSIZE        30
4470 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
4471 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
4472 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4473 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4474 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4475                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4476 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4477                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4478 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4479                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4480 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4481                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4482 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4483                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4484 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4485                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4486 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4487                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4488 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4489                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4490
4491 static struct
4492 {
4493   int xpos, ypos;
4494   int x, y;
4495   int width, height;
4496   int gadget_id;
4497   char *infotext;
4498 } toolbutton_info[NUM_TOOL_BUTTONS] =
4499 {
4500   {
4501     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
4502     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
4503     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
4504     TOOL_CTRL_ID_YES,
4505     "yes"
4506   },
4507   {
4508     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
4509     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
4510     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
4511     TOOL_CTRL_ID_NO,
4512     "no"
4513   },
4514   {
4515     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
4516     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
4517     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
4518     TOOL_CTRL_ID_CONFIRM,
4519     "confirm"
4520   },
4521   {
4522     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4523     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
4524     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4525     TOOL_CTRL_ID_PLAYER_1,
4526     "player 1"
4527   },
4528   {
4529     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4530     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
4531     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4532     TOOL_CTRL_ID_PLAYER_2,
4533     "player 2"
4534   },
4535   {
4536     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4537     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
4538     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4539     TOOL_CTRL_ID_PLAYER_3,
4540     "player 3"
4541   },
4542   {
4543     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4544     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
4545     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4546     TOOL_CTRL_ID_PLAYER_4,
4547     "player 4"
4548   }
4549 };
4550
4551 void CreateToolButtons()
4552 {
4553   int i;
4554
4555   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4556   {
4557     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4558     Bitmap *deco_bitmap = None;
4559     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4560     struct GadgetInfo *gi;
4561     unsigned long event_mask;
4562     int gd_xoffset, gd_yoffset;
4563     int gd_x1, gd_x2, gd_y;
4564     int id = i;
4565
4566     event_mask = GD_EVENT_RELEASED;
4567
4568     gd_xoffset = toolbutton_info[i].xpos;
4569     gd_yoffset = toolbutton_info[i].ypos;
4570     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4571     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4572     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4573
4574     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4575     {
4576       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4577
4578       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4579                            &deco_bitmap, &deco_x, &deco_y);
4580       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4581       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4582     }
4583
4584     gi = CreateGadget(GDI_CUSTOM_ID, id,
4585                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4586                       GDI_X, DX + toolbutton_info[i].x,
4587                       GDI_Y, DY + toolbutton_info[i].y,
4588                       GDI_WIDTH, toolbutton_info[i].width,
4589                       GDI_HEIGHT, toolbutton_info[i].height,
4590                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4591                       GDI_STATE, GD_BUTTON_UNPRESSED,
4592                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4593                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4594                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4595                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4596                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4597                       GDI_DECORATION_SHIFTING, 1, 1,
4598                       GDI_DIRECT_DRAW, FALSE,
4599                       GDI_EVENT_MASK, event_mask,
4600                       GDI_CALLBACK_ACTION, HandleToolButtons,
4601                       GDI_END);
4602
4603     if (gi == NULL)
4604       Error(ERR_EXIT, "cannot create gadget");
4605
4606     tool_gadget[id] = gi;
4607   }
4608 }
4609
4610 void FreeToolButtons()
4611 {
4612   int i;
4613
4614   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4615     FreeGadget(tool_gadget[i]);
4616 }
4617
4618 static void UnmapToolButtons()
4619 {
4620   int i;
4621
4622   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4623     UnmapGadget(tool_gadget[i]);
4624 }
4625
4626 static void HandleToolButtons(struct GadgetInfo *gi)
4627 {
4628   request_gadget_id = gi->custom_id;
4629 }
4630
4631 static struct Mapping_EM_to_RND_object
4632 {
4633   int element_em;
4634   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
4635   boolean is_backside;                  /* backside of moving element */
4636
4637   int element_rnd;
4638   int action;
4639   int direction;
4640 }
4641 em_object_mapping_list[] =
4642 {
4643   {
4644     Xblank,                             TRUE,   FALSE,
4645     EL_EMPTY,                           -1, -1
4646   },
4647   {
4648     Yacid_splash_eB,                    FALSE,  FALSE,
4649     EL_ACID_SPLASH_RIGHT,               -1, -1
4650   },
4651   {
4652     Yacid_splash_wB,                    FALSE,  FALSE,
4653     EL_ACID_SPLASH_LEFT,                -1, -1
4654   },
4655
4656 #ifdef EM_ENGINE_BAD_ROLL
4657   {
4658     Xstone_force_e,                     FALSE,  FALSE,
4659     EL_ROCK,                            -1, MV_BIT_RIGHT
4660   },
4661   {
4662     Xstone_force_w,                     FALSE,  FALSE,
4663     EL_ROCK,                            -1, MV_BIT_LEFT
4664   },
4665   {
4666     Xnut_force_e,                       FALSE,  FALSE,
4667     EL_NUT,                             -1, MV_BIT_RIGHT
4668   },
4669   {
4670     Xnut_force_w,                       FALSE,  FALSE,
4671     EL_NUT,                             -1, MV_BIT_LEFT
4672   },
4673   {
4674     Xspring_force_e,                    FALSE,  FALSE,
4675     EL_SPRING,                          -1, MV_BIT_RIGHT
4676   },
4677   {
4678     Xspring_force_w,                    FALSE,  FALSE,
4679     EL_SPRING,                          -1, MV_BIT_LEFT
4680   },
4681   {
4682     Xemerald_force_e,                   FALSE,  FALSE,
4683     EL_EMERALD,                         -1, MV_BIT_RIGHT
4684   },
4685   {
4686     Xemerald_force_w,                   FALSE,  FALSE,
4687     EL_EMERALD,                         -1, MV_BIT_LEFT
4688   },
4689   {
4690     Xdiamond_force_e,                   FALSE,  FALSE,
4691     EL_DIAMOND,                         -1, MV_BIT_RIGHT
4692   },
4693   {
4694     Xdiamond_force_w,                   FALSE,  FALSE,
4695     EL_DIAMOND,                         -1, MV_BIT_LEFT
4696   },
4697   {
4698     Xbomb_force_e,                      FALSE,  FALSE,
4699     EL_BOMB,                            -1, MV_BIT_RIGHT
4700   },
4701   {
4702     Xbomb_force_w,                      FALSE,  FALSE,
4703     EL_BOMB,                            -1, MV_BIT_LEFT
4704   },
4705 #endif  /* EM_ENGINE_BAD_ROLL */
4706
4707   {
4708     Xstone,                             TRUE,   FALSE,
4709     EL_ROCK,                            -1, -1
4710   },
4711   {
4712     Xstone_pause,                       FALSE,  FALSE,
4713     EL_ROCK,                            -1, -1
4714   },
4715   {
4716     Xstone_fall,                        FALSE,  FALSE,
4717     EL_ROCK,                            -1, -1
4718   },
4719   {
4720     Ystone_s,                           FALSE,  FALSE,
4721     EL_ROCK,                            ACTION_FALLING, -1
4722   },
4723   {
4724     Ystone_sB,                          FALSE,  TRUE,
4725     EL_ROCK,                            ACTION_FALLING, -1
4726   },
4727   {
4728     Ystone_e,                           FALSE,  FALSE,
4729     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4730   },
4731   {
4732     Ystone_eB,                          FALSE,  TRUE,
4733     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4734   },
4735   {
4736     Ystone_w,                           FALSE,  FALSE,
4737     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4738   },
4739   {
4740     Ystone_wB,                          FALSE,  TRUE,
4741     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4742   },
4743   {
4744     Xnut,                               TRUE,   FALSE,
4745     EL_NUT,                             -1, -1
4746   },
4747   {
4748     Xnut_pause,                         FALSE,  FALSE,
4749     EL_NUT,                             -1, -1
4750   },
4751   {
4752     Xnut_fall,                          FALSE,  FALSE,
4753     EL_NUT,                             -1, -1
4754   },
4755   {
4756     Ynut_s,                             FALSE,  FALSE,
4757     EL_NUT,                             ACTION_FALLING, -1
4758   },
4759   {
4760     Ynut_sB,                            FALSE,  TRUE,
4761     EL_NUT,                             ACTION_FALLING, -1
4762   },
4763   {
4764     Ynut_e,                             FALSE,  FALSE,
4765     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4766   },
4767   {
4768     Ynut_eB,                            FALSE,  TRUE,
4769     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4770   },
4771   {
4772     Ynut_w,                             FALSE,  FALSE,
4773     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4774   },
4775   {
4776     Ynut_wB,                            FALSE,  TRUE,
4777     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4778   },
4779   {
4780     Xbug_n,                             TRUE,   FALSE,
4781     EL_BUG_UP,                          -1, -1
4782   },
4783   {
4784     Xbug_e,                             TRUE,   FALSE,
4785     EL_BUG_RIGHT,                       -1, -1
4786   },
4787   {
4788     Xbug_s,                             TRUE,   FALSE,
4789     EL_BUG_DOWN,                        -1, -1
4790   },
4791   {
4792     Xbug_w,                             TRUE,   FALSE,
4793     EL_BUG_LEFT,                        -1, -1
4794   },
4795   {
4796     Xbug_gon,                           FALSE,  FALSE,
4797     EL_BUG_UP,                          -1, -1
4798   },
4799   {
4800     Xbug_goe,                           FALSE,  FALSE,
4801     EL_BUG_RIGHT,                       -1, -1
4802   },
4803   {
4804     Xbug_gos,                           FALSE,  FALSE,
4805     EL_BUG_DOWN,                        -1, -1
4806   },
4807   {
4808     Xbug_gow,                           FALSE,  FALSE,
4809     EL_BUG_LEFT,                        -1, -1
4810   },
4811   {
4812     Ybug_n,                             FALSE,  FALSE,
4813     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4814   },
4815   {
4816     Ybug_nB,                            FALSE,  TRUE,
4817     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4818   },
4819   {
4820     Ybug_e,                             FALSE,  FALSE,
4821     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4822   },
4823   {
4824     Ybug_eB,                            FALSE,  TRUE,
4825     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4826   },
4827   {
4828     Ybug_s,                             FALSE,  FALSE,
4829     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4830   },
4831   {
4832     Ybug_sB,                            FALSE,  TRUE,
4833     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4834   },
4835   {
4836     Ybug_w,                             FALSE,  FALSE,
4837     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4838   },
4839   {
4840     Ybug_wB,                            FALSE,  TRUE,
4841     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4842   },
4843   {
4844     Ybug_w_n,                           FALSE,  FALSE,
4845     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4846   },
4847   {
4848     Ybug_n_e,                           FALSE,  FALSE,
4849     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4850   },
4851   {
4852     Ybug_e_s,                           FALSE,  FALSE,
4853     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4854   },
4855   {
4856     Ybug_s_w,                           FALSE,  FALSE,
4857     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4858   },
4859   {
4860     Ybug_e_n,                           FALSE,  FALSE,
4861     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4862   },
4863   {
4864     Ybug_s_e,                           FALSE,  FALSE,
4865     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4866   },
4867   {
4868     Ybug_w_s,                           FALSE,  FALSE,
4869     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4870   },
4871   {
4872     Ybug_n_w,                           FALSE,  FALSE,
4873     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4874   },
4875   {
4876     Ybug_stone,                         FALSE,  FALSE,
4877     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
4878   },
4879   {
4880     Ybug_spring,                        FALSE,  FALSE,
4881     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
4882   },
4883   {
4884     Xtank_n,                            TRUE,   FALSE,
4885     EL_SPACESHIP_UP,                    -1, -1
4886   },
4887   {
4888     Xtank_e,                            TRUE,   FALSE,
4889     EL_SPACESHIP_RIGHT,                 -1, -1
4890   },
4891   {
4892     Xtank_s,                            TRUE,   FALSE,
4893     EL_SPACESHIP_DOWN,                  -1, -1
4894   },
4895   {
4896     Xtank_w,                            TRUE,   FALSE,
4897     EL_SPACESHIP_LEFT,                  -1, -1
4898   },
4899   {
4900     Xtank_gon,                          FALSE,  FALSE,
4901     EL_SPACESHIP_UP,                    -1, -1
4902   },
4903   {
4904     Xtank_goe,                          FALSE,  FALSE,
4905     EL_SPACESHIP_RIGHT,                 -1, -1
4906   },
4907   {
4908     Xtank_gos,                          FALSE,  FALSE,
4909     EL_SPACESHIP_DOWN,                  -1, -1
4910   },
4911   {
4912     Xtank_gow,                          FALSE,  FALSE,
4913     EL_SPACESHIP_LEFT,                  -1, -1
4914   },
4915   {
4916     Ytank_n,                            FALSE,  FALSE,
4917     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4918   },
4919   {
4920     Ytank_nB,                           FALSE,  TRUE,
4921     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4922   },
4923   {
4924     Ytank_e,                            FALSE,  FALSE,
4925     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4926   },
4927   {
4928     Ytank_eB,                           FALSE,  TRUE,
4929     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4930   },
4931   {
4932     Ytank_s,                            FALSE,  FALSE,
4933     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4934   },
4935   {
4936     Ytank_sB,                           FALSE,  TRUE,
4937     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4938   },
4939   {
4940     Ytank_w,                            FALSE,  FALSE,
4941     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4942   },
4943   {
4944     Ytank_wB,                           FALSE,  TRUE,
4945     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4946   },
4947   {
4948     Ytank_w_n,                          FALSE,  FALSE,
4949     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4950   },
4951   {
4952     Ytank_n_e,                          FALSE,  FALSE,
4953     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4954   },
4955   {
4956     Ytank_e_s,                          FALSE,  FALSE,
4957     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4958   },
4959   {
4960     Ytank_s_w,                          FALSE,  FALSE,
4961     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4962   },
4963   {
4964     Ytank_e_n,                          FALSE,  FALSE,
4965     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4966   },
4967   {
4968     Ytank_s_e,                          FALSE,  FALSE,
4969     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4970   },
4971   {
4972     Ytank_w_s,                          FALSE,  FALSE,
4973     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4974   },
4975   {
4976     Ytank_n_w,                          FALSE,  FALSE,
4977     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4978   },
4979   {
4980     Ytank_stone,                        FALSE,  FALSE,
4981     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
4982   },
4983   {
4984     Ytank_spring,                       FALSE,  FALSE,
4985     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
4986   },
4987   {
4988     Xandroid,                           TRUE,   FALSE,
4989     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
4990   },
4991   {
4992     Xandroid_1_n,                       FALSE,  FALSE,
4993     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4994   },
4995   {
4996     Xandroid_2_n,                       FALSE,  FALSE,
4997     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4998   },
4999   {
5000     Xandroid_1_e,                       FALSE,  FALSE,
5001     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5002   },
5003   {
5004     Xandroid_2_e,                       FALSE,  FALSE,
5005     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5006   },
5007   {
5008     Xandroid_1_w,                       FALSE,  FALSE,
5009     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5010   },
5011   {
5012     Xandroid_2_w,                       FALSE,  FALSE,
5013     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5014   },
5015   {
5016     Xandroid_1_s,                       FALSE,  FALSE,
5017     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5018   },
5019   {
5020     Xandroid_2_s,                       FALSE,  FALSE,
5021     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5022   },
5023   {
5024     Yandroid_n,                         FALSE,  FALSE,
5025     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5026   },
5027   {
5028     Yandroid_nB,                        FALSE,  TRUE,
5029     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5030   },
5031   {
5032     Yandroid_ne,                        FALSE,  FALSE,
5033     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
5034   },
5035   {
5036     Yandroid_neB,                       FALSE,  TRUE,
5037     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
5038   },
5039   {
5040     Yandroid_e,                         FALSE,  FALSE,
5041     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5042   },
5043   {
5044     Yandroid_eB,                        FALSE,  TRUE,
5045     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5046   },
5047   {
5048     Yandroid_se,                        FALSE,  FALSE,
5049     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
5050   },
5051   {
5052     Yandroid_seB,                       FALSE,  TRUE,
5053     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5054   },
5055   {
5056     Yandroid_s,                         FALSE,  FALSE,
5057     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5058   },
5059   {
5060     Yandroid_sB,                        FALSE,  TRUE,
5061     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5062   },
5063   {
5064     Yandroid_sw,                        FALSE,  FALSE,
5065     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
5066   },
5067   {
5068     Yandroid_swB,                       FALSE,  TRUE,
5069     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
5070   },
5071   {
5072     Yandroid_w,                         FALSE,  FALSE,
5073     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5074   },
5075   {
5076     Yandroid_wB,                        FALSE,  TRUE,
5077     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5078   },
5079   {
5080     Yandroid_nw,                        FALSE,  FALSE,
5081     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
5082   },
5083   {
5084     Yandroid_nwB,                       FALSE,  TRUE,
5085     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
5086   },
5087   {
5088     Xspring,                            TRUE,   FALSE,
5089     EL_SPRING,                          -1, -1
5090   },
5091   {
5092     Xspring_pause,                      FALSE,  FALSE,
5093     EL_SPRING,                          -1, -1
5094   },
5095   {
5096     Xspring_e,                          FALSE,  FALSE,
5097     EL_SPRING,                          -1, -1
5098   },
5099   {
5100     Xspring_w,                          FALSE,  FALSE,
5101     EL_SPRING,                          -1, -1
5102   },
5103   {
5104     Xspring_fall,                       FALSE,  FALSE,
5105     EL_SPRING,                          -1, -1
5106   },
5107   {
5108     Yspring_s,                          FALSE,  FALSE,
5109     EL_SPRING,                          ACTION_FALLING, -1
5110   },
5111   {
5112     Yspring_sB,                         FALSE,  TRUE,
5113     EL_SPRING,                          ACTION_FALLING, -1
5114   },
5115   {
5116     Yspring_e,                          FALSE,  FALSE,
5117     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5118   },
5119   {
5120     Yspring_eB,                         FALSE,  TRUE,
5121     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5122   },
5123   {
5124     Yspring_w,                          FALSE,  FALSE,
5125     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5126   },
5127   {
5128     Yspring_wB,                         FALSE,  TRUE,
5129     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5130   },
5131   {
5132     Yspring_kill_e,                     FALSE,  FALSE,
5133     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5134   },
5135   {
5136     Yspring_kill_eB,                    FALSE,  TRUE,
5137     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5138   },
5139   {
5140     Yspring_kill_w,                     FALSE,  FALSE,
5141     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5142   },
5143   {
5144     Yspring_kill_wB,                    FALSE,  TRUE,
5145     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5146   },
5147   {
5148     Xeater_n,                           TRUE,   FALSE,
5149     EL_YAMYAM_UP,                       -1, -1
5150   },
5151   {
5152     Xeater_e,                           TRUE,   FALSE,
5153     EL_YAMYAM_RIGHT,                    -1, -1
5154   },
5155   {
5156     Xeater_w,                           TRUE,   FALSE,
5157     EL_YAMYAM_LEFT,                     -1, -1
5158   },
5159   {
5160     Xeater_s,                           TRUE,   FALSE,
5161     EL_YAMYAM_DOWN,                     -1, -1
5162   },
5163   {
5164     Yeater_n,                           FALSE,  FALSE,
5165     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5166   },
5167   {
5168     Yeater_nB,                          FALSE,  TRUE,
5169     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5170   },
5171   {
5172     Yeater_e,                           FALSE,  FALSE,
5173     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5174   },
5175   {
5176     Yeater_eB,                          FALSE,  TRUE,
5177     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5178   },
5179   {
5180     Yeater_s,                           FALSE,  FALSE,
5181     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5182   },
5183   {
5184     Yeater_sB,                          FALSE,  TRUE,
5185     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5186   },
5187   {
5188     Yeater_w,                           FALSE,  FALSE,
5189     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5190   },
5191   {
5192     Yeater_wB,                          FALSE,  TRUE,
5193     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5194   },
5195   {
5196     Yeater_stone,                       FALSE,  FALSE,
5197     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
5198   },
5199   {
5200     Yeater_spring,                      FALSE,  FALSE,
5201     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
5202   },
5203   {
5204     Xalien,                             TRUE,   FALSE,
5205     EL_ROBOT,                           -1, -1
5206   },
5207   {
5208     Xalien_pause,                       FALSE,  FALSE,
5209     EL_ROBOT,                           -1, -1
5210   },
5211   {
5212     Yalien_n,                           FALSE,  FALSE,
5213     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5214   },
5215   {
5216     Yalien_nB,                          FALSE,  TRUE,
5217     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5218   },
5219   {
5220     Yalien_e,                           FALSE,  FALSE,
5221     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5222   },
5223   {
5224     Yalien_eB,                          FALSE,  TRUE,
5225     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5226   },
5227   {
5228     Yalien_s,                           FALSE,  FALSE,
5229     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5230   },
5231   {
5232     Yalien_sB,                          FALSE,  TRUE,
5233     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5234   },
5235   {
5236     Yalien_w,                           FALSE,  FALSE,
5237     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5238   },
5239   {
5240     Yalien_wB,                          FALSE,  TRUE,
5241     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5242   },
5243   {
5244     Yalien_stone,                       FALSE,  FALSE,
5245     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
5246   },
5247   {
5248     Yalien_spring,                      FALSE,  FALSE,
5249     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
5250   },
5251   {
5252     Xemerald,                           TRUE,   FALSE,
5253     EL_EMERALD,                         -1, -1
5254   },
5255   {
5256     Xemerald_pause,                     FALSE,  FALSE,
5257     EL_EMERALD,                         -1, -1
5258   },
5259   {
5260     Xemerald_fall,                      FALSE,  FALSE,
5261     EL_EMERALD,                         -1, -1
5262   },
5263   {
5264     Xemerald_shine,                     FALSE,  FALSE,
5265     EL_EMERALD,                         ACTION_TWINKLING, -1
5266   },
5267   {
5268     Yemerald_s,                         FALSE,  FALSE,
5269     EL_EMERALD,                         ACTION_FALLING, -1
5270   },
5271   {
5272     Yemerald_sB,                        FALSE,  TRUE,
5273     EL_EMERALD,                         ACTION_FALLING, -1
5274   },
5275   {
5276     Yemerald_e,                         FALSE,  FALSE,
5277     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5278   },
5279   {
5280     Yemerald_eB,                        FALSE,  TRUE,
5281     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5282   },
5283   {
5284     Yemerald_w,                         FALSE,  FALSE,
5285     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5286   },
5287   {
5288     Yemerald_wB,                        FALSE,  TRUE,
5289     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5290   },
5291   {
5292     Yemerald_eat,                       FALSE,  FALSE,
5293     EL_EMERALD,                         ACTION_COLLECTING, -1
5294   },
5295   {
5296     Yemerald_stone,                     FALSE,  FALSE,
5297     EL_NUT,                             ACTION_BREAKING, -1
5298   },
5299   {
5300     Xdiamond,                           TRUE,   FALSE,
5301     EL_DIAMOND,                         -1, -1
5302   },
5303   {
5304     Xdiamond_pause,                     FALSE,  FALSE,
5305     EL_DIAMOND,                         -1, -1
5306   },
5307   {
5308     Xdiamond_fall,                      FALSE,  FALSE,
5309     EL_DIAMOND,                         -1, -1
5310   },
5311   {
5312     Xdiamond_shine,                     FALSE,  FALSE,
5313     EL_DIAMOND,                         ACTION_TWINKLING, -1
5314   },
5315   {
5316     Ydiamond_s,                         FALSE,  FALSE,
5317     EL_DIAMOND,                         ACTION_FALLING, -1
5318   },
5319   {
5320     Ydiamond_sB,                        FALSE,  TRUE,
5321     EL_DIAMOND,                         ACTION_FALLING, -1
5322   },
5323   {
5324     Ydiamond_e,                         FALSE,  FALSE,
5325     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5326   },
5327   {
5328     Ydiamond_eB,                        FALSE,  TRUE,
5329     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5330   },
5331   {
5332     Ydiamond_w,                         FALSE,  FALSE,
5333     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5334   },
5335   {
5336     Ydiamond_wB,                        FALSE,  TRUE,
5337     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5338   },
5339   {
5340     Ydiamond_eat,                       FALSE,  FALSE,
5341     EL_DIAMOND,                         ACTION_COLLECTING, -1
5342   },
5343   {
5344     Ydiamond_stone,                     FALSE,  FALSE,
5345     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
5346   },
5347   {
5348     Xdrip_fall,                         TRUE,   FALSE,
5349     EL_AMOEBA_DROP,                     -1, -1
5350   },
5351   {
5352     Xdrip_stretch,                      FALSE,  FALSE,
5353     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5354   },
5355   {
5356     Xdrip_stretchB,                     FALSE,  TRUE,
5357     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5358   },
5359   {
5360     Xdrip_eat,                          FALSE,  FALSE,
5361     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
5362   },
5363   {
5364     Ydrip_s1,                           FALSE,  FALSE,
5365     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5366   },
5367   {
5368     Ydrip_s1B,                          FALSE,  TRUE,
5369     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5370   },
5371   {
5372     Ydrip_s2,                           FALSE,  FALSE,
5373     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5374   },
5375   {
5376     Ydrip_s2B,                          FALSE,  TRUE,
5377     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5378   },
5379   {
5380     Xbomb,                              TRUE,   FALSE,
5381     EL_BOMB,                            -1, -1
5382   },
5383   {
5384     Xbomb_pause,                        FALSE,  FALSE,
5385     EL_BOMB,                            -1, -1
5386   },
5387   {
5388     Xbomb_fall,                         FALSE,  FALSE,
5389     EL_BOMB,                            -1, -1
5390   },
5391   {
5392     Ybomb_s,                            FALSE,  FALSE,
5393     EL_BOMB,                            ACTION_FALLING, -1
5394   },
5395   {
5396     Ybomb_sB,                           FALSE,  TRUE,
5397     EL_BOMB,                            ACTION_FALLING, -1
5398   },
5399   {
5400     Ybomb_e,                            FALSE,  FALSE,
5401     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5402   },
5403   {
5404     Ybomb_eB,                           FALSE,  TRUE,
5405     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5406   },
5407   {
5408     Ybomb_w,                            FALSE,  FALSE,
5409     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5410   },
5411   {
5412     Ybomb_wB,                           FALSE,  TRUE,
5413     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5414   },
5415   {
5416     Ybomb_eat,                          FALSE,  FALSE,
5417     EL_BOMB,                            ACTION_ACTIVATING, -1
5418   },
5419   {
5420     Xballoon,                           TRUE,   FALSE,
5421     EL_BALLOON,                         -1, -1
5422   },
5423   {
5424     Yballoon_n,                         FALSE,  FALSE,
5425     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5426   },
5427   {
5428     Yballoon_nB,                        FALSE,  TRUE,
5429     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5430   },
5431   {
5432     Yballoon_e,                         FALSE,  FALSE,
5433     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5434   },
5435   {
5436     Yballoon_eB,                        FALSE,  TRUE,
5437     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5438   },
5439   {
5440     Yballoon_s,                         FALSE,  FALSE,
5441     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5442   },
5443   {
5444     Yballoon_sB,                        FALSE,  TRUE,
5445     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5446   },
5447   {
5448     Yballoon_w,                         FALSE,  FALSE,
5449     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5450   },
5451   {
5452     Yballoon_wB,                        FALSE,  TRUE,
5453     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5454   },
5455   {
5456     Xgrass,                             TRUE,   FALSE,
5457     EL_EMC_GRASS,                       -1, -1
5458   },
5459   {
5460     Ygrass_nB,                          FALSE,  FALSE,
5461     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
5462   },
5463   {
5464     Ygrass_eB,                          FALSE,  FALSE,
5465     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
5466   },
5467   {
5468     Ygrass_sB,                          FALSE,  FALSE,
5469     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
5470   },
5471   {
5472     Ygrass_wB,                          FALSE,  FALSE,
5473     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
5474   },
5475   {
5476     Xdirt,                              TRUE,   FALSE,
5477     EL_SAND,                            -1, -1
5478   },
5479   {
5480     Ydirt_nB,                           FALSE,  FALSE,
5481     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
5482   },
5483   {
5484     Ydirt_eB,                           FALSE,  FALSE,
5485     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
5486   },
5487   {
5488     Ydirt_sB,                           FALSE,  FALSE,
5489     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
5490   },
5491   {
5492     Ydirt_wB,                           FALSE,  FALSE,
5493     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
5494   },
5495   {
5496     Xacid_ne,                           TRUE,   FALSE,
5497     EL_ACID_POOL_TOPRIGHT,              -1, -1
5498   },
5499   {
5500     Xacid_se,                           TRUE,   FALSE,
5501     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
5502   },
5503   {
5504     Xacid_s,                            TRUE,   FALSE,
5505     EL_ACID_POOL_BOTTOM,                -1, -1
5506   },
5507   {
5508     Xacid_sw,                           TRUE,   FALSE,
5509     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
5510   },
5511   {
5512     Xacid_nw,                           TRUE,   FALSE,
5513     EL_ACID_POOL_TOPLEFT,               -1, -1
5514   },
5515   {
5516     Xacid_1,                            TRUE,   FALSE,
5517     EL_ACID,                            -1, -1
5518   },
5519   {
5520     Xacid_2,                            FALSE,  FALSE,
5521     EL_ACID,                            -1, -1
5522   },
5523   {
5524     Xacid_3,                            FALSE,  FALSE,
5525     EL_ACID,                            -1, -1
5526   },
5527   {
5528     Xacid_4,                            FALSE,  FALSE,
5529     EL_ACID,                            -1, -1
5530   },
5531   {
5532     Xacid_5,                            FALSE,  FALSE,
5533     EL_ACID,                            -1, -1
5534   },
5535   {
5536     Xacid_6,                            FALSE,  FALSE,
5537     EL_ACID,                            -1, -1
5538   },
5539   {
5540     Xacid_7,                            FALSE,  FALSE,
5541     EL_ACID,                            -1, -1
5542   },
5543   {
5544     Xacid_8,                            FALSE,  FALSE,
5545     EL_ACID,                            -1, -1
5546   },
5547   {
5548     Xball_1,                            TRUE,   FALSE,
5549     EL_EMC_MAGIC_BALL,                  -1, -1
5550   },
5551   {
5552     Xball_1B,                           FALSE,  FALSE,
5553     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5554   },
5555   {
5556     Xball_2,                            FALSE,  FALSE,
5557     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5558   },
5559   {
5560     Xball_2B,                           FALSE,  FALSE,
5561     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5562   },
5563   {
5564     Yball_eat,                          FALSE,  FALSE,
5565     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
5566   },
5567   {
5568     Ykey_1_eat,                         FALSE,  FALSE,
5569     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
5570   },
5571   {
5572     Ykey_2_eat,                         FALSE,  FALSE,
5573     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
5574   },
5575   {
5576     Ykey_3_eat,                         FALSE,  FALSE,
5577     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
5578   },
5579   {
5580     Ykey_4_eat,                         FALSE,  FALSE,
5581     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
5582   },
5583   {
5584     Ykey_5_eat,                         FALSE,  FALSE,
5585     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
5586   },
5587   {
5588     Ykey_6_eat,                         FALSE,  FALSE,
5589     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
5590   },
5591   {
5592     Ykey_7_eat,                         FALSE,  FALSE,
5593     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
5594   },
5595   {
5596     Ykey_8_eat,                         FALSE,  FALSE,
5597     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
5598   },
5599   {
5600     Ylenses_eat,                        FALSE,  FALSE,
5601     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
5602   },
5603   {
5604     Ymagnify_eat,                       FALSE,  FALSE,
5605     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
5606   },
5607   {
5608     Ygrass_eat,                         FALSE,  FALSE,
5609     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
5610   },
5611   {
5612     Ydirt_eat,                          FALSE,  FALSE,
5613     EL_SAND,                            ACTION_SNAPPING, -1
5614   },
5615   {
5616     Xgrow_ns,                           TRUE,   FALSE,
5617     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
5618   },
5619   {
5620     Ygrow_ns_eat,                       FALSE,  FALSE,
5621     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
5622   },
5623   {
5624     Xgrow_ew,                           TRUE,   FALSE,
5625     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
5626   },
5627   {
5628     Ygrow_ew_eat,                       FALSE,  FALSE,
5629     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
5630   },
5631   {
5632     Xwonderwall,                        TRUE,   FALSE,
5633     EL_MAGIC_WALL,                      -1, -1
5634   },
5635   {
5636     XwonderwallB,                       FALSE,  FALSE,
5637     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
5638   },
5639   {
5640     Xamoeba_1,                          TRUE,   FALSE,
5641     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5642   },
5643   {
5644     Xamoeba_2,                          FALSE,  FALSE,
5645     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5646   },
5647   {
5648     Xamoeba_3,                          FALSE,  FALSE,
5649     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5650   },
5651   {
5652     Xamoeba_4,                          FALSE,  FALSE,
5653     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5654   },
5655   {
5656     Xamoeba_5,                          TRUE,   FALSE,
5657     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5658   },
5659   {
5660     Xamoeba_6,                          FALSE,  FALSE,
5661     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5662   },
5663   {
5664     Xamoeba_7,                          FALSE,  FALSE,
5665     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5666   },
5667   {
5668     Xamoeba_8,                          FALSE,  FALSE,
5669     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5670   },
5671   {
5672     Xdoor_1,                            TRUE,   FALSE,
5673     EL_EM_GATE_1,                       -1, -1
5674   },
5675   {
5676     Xdoor_2,                            TRUE,   FALSE,
5677     EL_EM_GATE_2,                       -1, -1
5678   },
5679   {
5680     Xdoor_3,                            TRUE,   FALSE,
5681     EL_EM_GATE_3,                       -1, -1
5682   },
5683   {
5684     Xdoor_4,                            TRUE,   FALSE,
5685     EL_EM_GATE_4,                       -1, -1
5686   },
5687   {
5688     Xdoor_5,                            TRUE,   FALSE,
5689     EL_EMC_GATE_5,                      -1, -1
5690   },
5691   {
5692     Xdoor_6,                            TRUE,   FALSE,
5693     EL_EMC_GATE_6,                      -1, -1
5694   },
5695   {
5696     Xdoor_7,                            TRUE,   FALSE,
5697     EL_EMC_GATE_7,                      -1, -1
5698   },
5699   {
5700     Xdoor_8,                            TRUE,   FALSE,
5701     EL_EMC_GATE_8,                      -1, -1
5702   },
5703   {
5704     Xkey_1,                             TRUE,   FALSE,
5705     EL_EM_KEY_1,                        -1, -1
5706   },
5707   {
5708     Xkey_2,                             TRUE,   FALSE,
5709     EL_EM_KEY_2,                        -1, -1
5710   },
5711   {
5712     Xkey_3,                             TRUE,   FALSE,
5713     EL_EM_KEY_3,                        -1, -1
5714   },
5715   {
5716     Xkey_4,                             TRUE,   FALSE,
5717     EL_EM_KEY_4,                        -1, -1
5718   },
5719   {
5720     Xkey_5,                             TRUE,   FALSE,
5721     EL_EMC_KEY_5,                       -1, -1
5722   },
5723   {
5724     Xkey_6,                             TRUE,   FALSE,
5725     EL_EMC_KEY_6,                       -1, -1
5726   },
5727   {
5728     Xkey_7,                             TRUE,   FALSE,
5729     EL_EMC_KEY_7,                       -1, -1
5730   },
5731   {
5732     Xkey_8,                             TRUE,   FALSE,
5733     EL_EMC_KEY_8,                       -1, -1
5734   },
5735   {
5736     Xwind_n,                            TRUE,   FALSE,
5737     EL_BALLOON_SWITCH_UP,               -1, -1
5738   },
5739   {
5740     Xwind_e,                            TRUE,   FALSE,
5741     EL_BALLOON_SWITCH_RIGHT,            -1, -1
5742   },
5743   {
5744     Xwind_s,                            TRUE,   FALSE,
5745     EL_BALLOON_SWITCH_DOWN,             -1, -1
5746   },
5747   {
5748     Xwind_w,                            TRUE,   FALSE,
5749     EL_BALLOON_SWITCH_LEFT,             -1, -1
5750   },
5751   {
5752     Xwind_nesw,                         TRUE,   FALSE,
5753     EL_BALLOON_SWITCH_ANY,              -1, -1
5754   },
5755   {
5756     Xwind_stop,                         TRUE,   FALSE,
5757     EL_BALLOON_SWITCH_NONE,             -1, -1
5758   },
5759   {
5760     Xexit,                              TRUE,   FALSE,
5761     EL_EM_EXIT_CLOSED,                  -1, -1
5762   },
5763   {
5764     Xexit_1,                            TRUE,   FALSE,
5765     EL_EM_EXIT_OPEN,                    -1, -1
5766   },
5767   {
5768     Xexit_2,                            FALSE,  FALSE,
5769     EL_EM_EXIT_OPEN,                    -1, -1
5770   },
5771   {
5772     Xexit_3,                            FALSE,  FALSE,
5773     EL_EM_EXIT_OPEN,                    -1, -1
5774   },
5775   {
5776     Xdynamite,                          TRUE,   FALSE,
5777     EL_EM_DYNAMITE,                     -1, -1
5778   },
5779   {
5780     Ydynamite_eat,                      FALSE,  FALSE,
5781     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
5782   },
5783   {
5784     Xdynamite_1,                        TRUE,   FALSE,
5785     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5786   },
5787   {
5788     Xdynamite_2,                        FALSE,  FALSE,
5789     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5790   },
5791   {
5792     Xdynamite_3,                        FALSE,  FALSE,
5793     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5794   },
5795   {
5796     Xdynamite_4,                        FALSE,  FALSE,
5797     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5798   },
5799   {
5800     Xbumper,                            TRUE,   FALSE,
5801     EL_EMC_SPRING_BUMPER,               -1, -1
5802   },
5803   {
5804     XbumperB,                           FALSE,  FALSE,
5805     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
5806   },
5807   {
5808     Xwheel,                             TRUE,   FALSE,
5809     EL_ROBOT_WHEEL,                     -1, -1
5810   },
5811   {
5812     XwheelB,                            FALSE,  FALSE,
5813     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
5814   },
5815   {
5816     Xswitch,                            TRUE,   FALSE,
5817     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
5818   },
5819   {
5820     XswitchB,                           FALSE,  FALSE,
5821     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
5822   },
5823   {
5824     Xsand,                              TRUE,   FALSE,
5825     EL_QUICKSAND_EMPTY,                 -1, -1
5826   },
5827   {
5828     Xsand_stone,                        TRUE,   FALSE,
5829     EL_QUICKSAND_FULL,                  -1, -1
5830   },
5831   {
5832     Xsand_stonein_1,                    FALSE,  TRUE,
5833     EL_ROCK,                            ACTION_FILLING, -1
5834   },
5835   {
5836     Xsand_stonein_2,                    FALSE,  TRUE,
5837     EL_ROCK,                            ACTION_FILLING, -1
5838   },
5839   {
5840     Xsand_stonein_3,                    FALSE,  TRUE,
5841     EL_ROCK,                            ACTION_FILLING, -1
5842   },
5843   {
5844     Xsand_stonein_4,                    FALSE,  TRUE,
5845     EL_ROCK,                            ACTION_FILLING, -1
5846   },
5847 #if 1
5848   {
5849     Xsand_stonesand_1,                  FALSE,  FALSE,
5850     EL_QUICKSAND_EMPTYING,              -1, -1
5851   },
5852   {
5853     Xsand_stonesand_2,                  FALSE,  FALSE,
5854     EL_QUICKSAND_EMPTYING,              -1, -1
5855   },
5856   {
5857     Xsand_stonesand_3,                  FALSE,  FALSE,
5858     EL_QUICKSAND_EMPTYING,              -1, -1
5859   },
5860   {
5861     Xsand_stonesand_4,                  FALSE,  FALSE,
5862     EL_QUICKSAND_EMPTYING,              -1, -1
5863   },
5864   {
5865     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
5866     EL_QUICKSAND_EMPTYING,              -1, -1
5867   },
5868   {
5869     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
5870     EL_QUICKSAND_EMPTYING,              -1, -1
5871   },
5872 #else
5873   {
5874     Xsand_stonesand_1,                  FALSE,  FALSE,
5875     EL_QUICKSAND_FULL,                  -1, -1
5876   },
5877   {
5878     Xsand_stonesand_2,                  FALSE,  FALSE,
5879     EL_QUICKSAND_FULL,                  -1, -1
5880   },
5881   {
5882     Xsand_stonesand_3,                  FALSE,  FALSE,
5883     EL_QUICKSAND_FULL,                  -1, -1
5884   },
5885   {
5886     Xsand_stonesand_4,                  FALSE,  FALSE,
5887     EL_QUICKSAND_FULL,                  -1, -1
5888   },
5889 #endif
5890   {
5891     Xsand_stoneout_1,                   FALSE,  FALSE,
5892     EL_ROCK,                            ACTION_EMPTYING, -1
5893   },
5894   {
5895     Xsand_stoneout_2,                   FALSE,  FALSE,
5896     EL_ROCK,                            ACTION_EMPTYING, -1
5897   },
5898 #if 1
5899   {
5900     Xsand_sandstone_1,                  FALSE,  FALSE,
5901     EL_QUICKSAND_FILLING,               -1, -1
5902   },
5903   {
5904     Xsand_sandstone_2,                  FALSE,  FALSE,
5905     EL_QUICKSAND_FILLING,               -1, -1
5906   },
5907   {
5908     Xsand_sandstone_3,                  FALSE,  FALSE,
5909     EL_QUICKSAND_FILLING,               -1, -1
5910   },
5911   {
5912     Xsand_sandstone_4,                  FALSE,  FALSE,
5913     EL_QUICKSAND_FILLING,               -1, -1
5914   },
5915 #else
5916   {
5917     Xsand_sandstone_1,                  FALSE,  FALSE,
5918     EL_QUICKSAND_FULL,                  -1, -1
5919   },
5920   {
5921     Xsand_sandstone_2,                  FALSE,  FALSE,
5922     EL_QUICKSAND_FULL,                  -1, -1
5923   },
5924   {
5925     Xsand_sandstone_3,                  FALSE,  FALSE,
5926     EL_QUICKSAND_FULL,                  -1, -1
5927   },
5928   {
5929     Xsand_sandstone_4,                  FALSE,  FALSE,
5930     EL_QUICKSAND_FULL,                  -1, -1
5931   },
5932 #endif
5933   {
5934     Xplant,                             TRUE,   FALSE,
5935     EL_EMC_PLANT,                       -1, -1
5936   },
5937   {
5938     Yplant,                             FALSE,  FALSE,
5939     EL_EMC_PLANT,                       -1, -1
5940   },
5941   {
5942     Xlenses,                            TRUE,   FALSE,
5943     EL_EMC_LENSES,                      -1, -1
5944   },
5945   {
5946     Xmagnify,                           TRUE,   FALSE,
5947     EL_EMC_MAGNIFIER,                   -1, -1
5948   },
5949   {
5950     Xdripper,                           TRUE,   FALSE,
5951     EL_EMC_DRIPPER,                     -1, -1
5952   },
5953   {
5954     XdripperB,                          FALSE,  FALSE,
5955     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
5956   },
5957   {
5958     Xfake_blank,                        TRUE,   FALSE,
5959     EL_INVISIBLE_WALL,                  -1, -1
5960   },
5961   {
5962     Xfake_blankB,                       FALSE,  FALSE,
5963     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
5964   },
5965   {
5966     Xfake_grass,                        TRUE,   FALSE,
5967     EL_EMC_FAKE_GRASS,                  -1, -1
5968   },
5969   {
5970     Xfake_grassB,                       FALSE,  FALSE,
5971     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
5972   },
5973   {
5974     Xfake_door_1,                       TRUE,   FALSE,
5975     EL_EM_GATE_1_GRAY,                  -1, -1
5976   },
5977   {
5978     Xfake_door_2,                       TRUE,   FALSE,
5979     EL_EM_GATE_2_GRAY,                  -1, -1
5980   },
5981   {
5982     Xfake_door_3,                       TRUE,   FALSE,
5983     EL_EM_GATE_3_GRAY,                  -1, -1
5984   },
5985   {
5986     Xfake_door_4,                       TRUE,   FALSE,
5987     EL_EM_GATE_4_GRAY,                  -1, -1
5988   },
5989   {
5990     Xfake_door_5,                       TRUE,   FALSE,
5991     EL_EMC_GATE_5_GRAY,                 -1, -1
5992   },
5993   {
5994     Xfake_door_6,                       TRUE,   FALSE,
5995     EL_EMC_GATE_6_GRAY,                 -1, -1
5996   },
5997   {
5998     Xfake_door_7,                       TRUE,   FALSE,
5999     EL_EMC_GATE_7_GRAY,                 -1, -1
6000   },
6001   {
6002     Xfake_door_8,                       TRUE,   FALSE,
6003     EL_EMC_GATE_8_GRAY,                 -1, -1
6004   },
6005   {
6006     Xfake_acid_1,                       TRUE,   FALSE,
6007     EL_EMC_FAKE_ACID,                   -1, -1
6008   },
6009   {
6010     Xfake_acid_2,                       FALSE,  FALSE,
6011     EL_EMC_FAKE_ACID,                   -1, -1
6012   },
6013   {
6014     Xfake_acid_3,                       FALSE,  FALSE,
6015     EL_EMC_FAKE_ACID,                   -1, -1
6016   },
6017   {
6018     Xfake_acid_4,                       FALSE,  FALSE,
6019     EL_EMC_FAKE_ACID,                   -1, -1
6020   },
6021   {
6022     Xfake_acid_5,                       FALSE,  FALSE,
6023     EL_EMC_FAKE_ACID,                   -1, -1
6024   },
6025   {
6026     Xfake_acid_6,                       FALSE,  FALSE,
6027     EL_EMC_FAKE_ACID,                   -1, -1
6028   },
6029   {
6030     Xfake_acid_7,                       FALSE,  FALSE,
6031     EL_EMC_FAKE_ACID,                   -1, -1
6032   },
6033   {
6034     Xfake_acid_8,                       FALSE,  FALSE,
6035     EL_EMC_FAKE_ACID,                   -1, -1
6036   },
6037   {
6038     Xsteel_1,                           TRUE,   FALSE,
6039     EL_STEELWALL,                       -1, -1
6040   },
6041   {
6042     Xsteel_2,                           TRUE,   FALSE,
6043     EL_EMC_STEELWALL_2,                 -1, -1
6044   },
6045   {
6046     Xsteel_3,                           TRUE,   FALSE,
6047     EL_EMC_STEELWALL_3,                 -1, -1
6048   },
6049   {
6050     Xsteel_4,                           TRUE,   FALSE,
6051     EL_EMC_STEELWALL_4,                 -1, -1
6052   },
6053   {
6054     Xwall_1,                            TRUE,   FALSE,
6055     EL_WALL,                            -1, -1
6056   },
6057   {
6058     Xwall_2,                            TRUE,   FALSE,
6059     EL_EMC_WALL_14,                     -1, -1
6060   },
6061   {
6062     Xwall_3,                            TRUE,   FALSE,
6063     EL_EMC_WALL_15,                     -1, -1
6064   },
6065   {
6066     Xwall_4,                            TRUE,   FALSE,
6067     EL_EMC_WALL_16,                     -1, -1
6068   },
6069   {
6070     Xround_wall_1,                      TRUE,   FALSE,
6071     EL_WALL_SLIPPERY,                   -1, -1
6072   },
6073   {
6074     Xround_wall_2,                      TRUE,   FALSE,
6075     EL_EMC_WALL_SLIPPERY_2,             -1, -1
6076   },
6077   {
6078     Xround_wall_3,                      TRUE,   FALSE,
6079     EL_EMC_WALL_SLIPPERY_3,             -1, -1
6080   },
6081   {
6082     Xround_wall_4,                      TRUE,   FALSE,
6083     EL_EMC_WALL_SLIPPERY_4,             -1, -1
6084   },
6085   {
6086     Xdecor_1,                           TRUE,   FALSE,
6087     EL_EMC_WALL_8,                      -1, -1
6088   },
6089   {
6090     Xdecor_2,                           TRUE,   FALSE,
6091     EL_EMC_WALL_6,                      -1, -1
6092   },
6093   {
6094     Xdecor_3,                           TRUE,   FALSE,
6095     EL_EMC_WALL_4,                      -1, -1
6096   },
6097   {
6098     Xdecor_4,                           TRUE,   FALSE,
6099     EL_EMC_WALL_7,                      -1, -1
6100   },
6101   {
6102     Xdecor_5,                           TRUE,   FALSE,
6103     EL_EMC_WALL_5,                      -1, -1
6104   },
6105   {
6106     Xdecor_6,                           TRUE,   FALSE,
6107     EL_EMC_WALL_9,                      -1, -1
6108   },
6109   {
6110     Xdecor_7,                           TRUE,   FALSE,
6111     EL_EMC_WALL_10,                     -1, -1
6112   },
6113   {
6114     Xdecor_8,                           TRUE,   FALSE,
6115     EL_EMC_WALL_1,                      -1, -1
6116   },
6117   {
6118     Xdecor_9,                           TRUE,   FALSE,
6119     EL_EMC_WALL_2,                      -1, -1
6120   },
6121   {
6122     Xdecor_10,                          TRUE,   FALSE,
6123     EL_EMC_WALL_3,                      -1, -1
6124   },
6125   {
6126     Xdecor_11,                          TRUE,   FALSE,
6127     EL_EMC_WALL_11,                     -1, -1
6128   },
6129   {
6130     Xdecor_12,                          TRUE,   FALSE,
6131     EL_EMC_WALL_12,                     -1, -1
6132   },
6133   {
6134     Xalpha_0,                           TRUE,   FALSE,
6135     EL_CHAR('0'),                       -1, -1
6136   },
6137   {
6138     Xalpha_1,                           TRUE,   FALSE,
6139     EL_CHAR('1'),                       -1, -1
6140   },
6141   {
6142     Xalpha_2,                           TRUE,   FALSE,
6143     EL_CHAR('2'),                       -1, -1
6144   },
6145   {
6146     Xalpha_3,                           TRUE,   FALSE,
6147     EL_CHAR('3'),                       -1, -1
6148   },
6149   {
6150     Xalpha_4,                           TRUE,   FALSE,
6151     EL_CHAR('4'),                       -1, -1
6152   },
6153   {
6154     Xalpha_5,                           TRUE,   FALSE,
6155     EL_CHAR('5'),                       -1, -1
6156   },
6157   {
6158     Xalpha_6,                           TRUE,   FALSE,
6159     EL_CHAR('6'),                       -1, -1
6160   },
6161   {
6162     Xalpha_7,                           TRUE,   FALSE,
6163     EL_CHAR('7'),                       -1, -1
6164   },
6165   {
6166     Xalpha_8,                           TRUE,   FALSE,
6167     EL_CHAR('8'),                       -1, -1
6168   },
6169   {
6170     Xalpha_9,                           TRUE,   FALSE,
6171     EL_CHAR('9'),                       -1, -1
6172   },
6173   {
6174     Xalpha_excla,                       TRUE,   FALSE,
6175     EL_CHAR('!'),                       -1, -1
6176   },
6177   {
6178     Xalpha_quote,                       TRUE,   FALSE,
6179     EL_CHAR('"'),                       -1, -1
6180   },
6181   {
6182     Xalpha_comma,                       TRUE,   FALSE,
6183     EL_CHAR(','),                       -1, -1
6184   },
6185   {
6186     Xalpha_minus,                       TRUE,   FALSE,
6187     EL_CHAR('-'),                       -1, -1
6188   },
6189   {
6190     Xalpha_perio,                       TRUE,   FALSE,
6191     EL_CHAR('.'),                       -1, -1
6192   },
6193   {
6194     Xalpha_colon,                       TRUE,   FALSE,
6195     EL_CHAR(':'),                       -1, -1
6196   },
6197   {
6198     Xalpha_quest,                       TRUE,   FALSE,
6199     EL_CHAR('?'),                       -1, -1
6200   },
6201   {
6202     Xalpha_a,                           TRUE,   FALSE,
6203     EL_CHAR('A'),                       -1, -1
6204   },
6205   {
6206     Xalpha_b,                           TRUE,   FALSE,
6207     EL_CHAR('B'),                       -1, -1
6208   },
6209   {
6210     Xalpha_c,                           TRUE,   FALSE,
6211     EL_CHAR('C'),                       -1, -1
6212   },
6213   {
6214     Xalpha_d,                           TRUE,   FALSE,
6215     EL_CHAR('D'),                       -1, -1
6216   },
6217   {
6218     Xalpha_e,                           TRUE,   FALSE,
6219     EL_CHAR('E'),                       -1, -1
6220   },
6221   {
6222     Xalpha_f,                           TRUE,   FALSE,
6223     EL_CHAR('F'),                       -1, -1
6224   },
6225   {
6226     Xalpha_g,                           TRUE,   FALSE,
6227     EL_CHAR('G'),                       -1, -1
6228   },
6229   {
6230     Xalpha_h,                           TRUE,   FALSE,
6231     EL_CHAR('H'),                       -1, -1
6232   },
6233   {
6234     Xalpha_i,                           TRUE,   FALSE,
6235     EL_CHAR('I'),                       -1, -1
6236   },
6237   {
6238     Xalpha_j,                           TRUE,   FALSE,
6239     EL_CHAR('J'),                       -1, -1
6240   },
6241   {
6242     Xalpha_k,                           TRUE,   FALSE,
6243     EL_CHAR('K'),                       -1, -1
6244   },
6245   {
6246     Xalpha_l,                           TRUE,   FALSE,
6247     EL_CHAR('L'),                       -1, -1
6248   },
6249   {
6250     Xalpha_m,                           TRUE,   FALSE,
6251     EL_CHAR('M'),                       -1, -1
6252   },
6253   {
6254     Xalpha_n,                           TRUE,   FALSE,
6255     EL_CHAR('N'),                       -1, -1
6256   },
6257   {
6258     Xalpha_o,                           TRUE,   FALSE,
6259     EL_CHAR('O'),                       -1, -1
6260   },
6261   {
6262     Xalpha_p,                           TRUE,   FALSE,
6263     EL_CHAR('P'),                       -1, -1
6264   },
6265   {
6266     Xalpha_q,                           TRUE,   FALSE,
6267     EL_CHAR('Q'),                       -1, -1
6268   },
6269   {
6270     Xalpha_r,                           TRUE,   FALSE,
6271     EL_CHAR('R'),                       -1, -1
6272   },
6273   {
6274     Xalpha_s,                           TRUE,   FALSE,
6275     EL_CHAR('S'),                       -1, -1
6276   },
6277   {
6278     Xalpha_t,                           TRUE,   FALSE,
6279     EL_CHAR('T'),                       -1, -1
6280   },
6281   {
6282     Xalpha_u,                           TRUE,   FALSE,
6283     EL_CHAR('U'),                       -1, -1
6284   },
6285   {
6286     Xalpha_v,                           TRUE,   FALSE,
6287     EL_CHAR('V'),                       -1, -1
6288   },
6289   {
6290     Xalpha_w,                           TRUE,   FALSE,
6291     EL_CHAR('W'),                       -1, -1
6292   },
6293   {
6294     Xalpha_x,                           TRUE,   FALSE,
6295     EL_CHAR('X'),                       -1, -1
6296   },
6297   {
6298     Xalpha_y,                           TRUE,   FALSE,
6299     EL_CHAR('Y'),                       -1, -1
6300   },
6301   {
6302     Xalpha_z,                           TRUE,   FALSE,
6303     EL_CHAR('Z'),                       -1, -1
6304   },
6305   {
6306     Xalpha_arrow_e,                     TRUE,   FALSE,
6307     EL_CHAR('>'),                       -1, -1
6308   },
6309   {
6310     Xalpha_arrow_w,                     TRUE,   FALSE,
6311     EL_CHAR('<'),                       -1, -1
6312   },
6313   {
6314     Xalpha_copyr,                       TRUE,   FALSE,
6315     EL_CHAR('©'),                       -1, -1
6316   },
6317
6318   {
6319     Xboom_bug,                          FALSE,  FALSE,
6320     EL_BUG,                             ACTION_EXPLODING, -1
6321   },
6322   {
6323     Xboom_bomb,                         FALSE,  FALSE,
6324     EL_BOMB,                            ACTION_EXPLODING, -1
6325   },
6326   {
6327     Xboom_android,                      FALSE,  FALSE,
6328     EL_EMC_ANDROID,                     ACTION_OTHER, -1
6329   },
6330   {
6331     Xboom_1,                            FALSE,  FALSE,
6332     EL_DEFAULT,                         ACTION_EXPLODING, -1
6333   },
6334   {
6335     Xboom_2,                            FALSE,  FALSE,
6336     EL_DEFAULT,                         ACTION_EXPLODING, -1
6337   },
6338   {
6339     Znormal,                            FALSE,  FALSE,
6340     EL_EMPTY,                           -1, -1
6341   },
6342   {
6343     Zdynamite,                          FALSE,  FALSE,
6344     EL_EMPTY,                           -1, -1
6345   },
6346   {
6347     Zplayer,                            FALSE,  FALSE,
6348     EL_EMPTY,                           -1, -1
6349   },
6350   {
6351     ZBORDER,                            FALSE,  FALSE,
6352     EL_EMPTY,                           -1, -1
6353   },
6354
6355   {
6356     -1,                                 FALSE,  FALSE,
6357     -1,                                 -1, -1
6358   }
6359 };
6360
6361 static struct Mapping_EM_to_RND_player
6362 {
6363   int action_em;
6364   int player_nr;
6365
6366   int element_rnd;
6367   int action;
6368   int direction;
6369 }
6370 em_player_mapping_list[] =
6371 {
6372   {
6373     SPR_walk + 0,                       0,
6374     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
6375   },
6376   {
6377     SPR_walk + 1,                       0,
6378     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
6379   },
6380   {
6381     SPR_walk + 2,                       0,
6382     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
6383   },
6384   {
6385     SPR_walk + 3,                       0,
6386     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
6387   },
6388   {
6389     SPR_push + 0,                       0,
6390     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
6391   },
6392   {
6393     SPR_push + 1,                       0,
6394     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
6395   },
6396   {
6397     SPR_push + 2,                       0,
6398     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
6399   },
6400   {
6401     SPR_push + 3,                       0,
6402     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
6403   },
6404   {
6405     SPR_spray + 0,                      0,
6406     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
6407   },
6408   {
6409     SPR_spray + 1,                      0,
6410     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6411   },
6412   {
6413     SPR_spray + 2,                      0,
6414     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
6415   },
6416   {
6417     SPR_spray + 3,                      0,
6418     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
6419   },
6420   {
6421     SPR_walk + 0,                       1,
6422     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
6423   },
6424   {
6425     SPR_walk + 1,                       1,
6426     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
6427   },
6428   {
6429     SPR_walk + 2,                       1,
6430     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
6431   },
6432   {
6433     SPR_walk + 3,                       1,
6434     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
6435   },
6436   {
6437     SPR_push + 0,                       1,
6438     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
6439   },
6440   {
6441     SPR_push + 1,                       1,
6442     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
6443   },
6444   {
6445     SPR_push + 2,                       1,
6446     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
6447   },
6448   {
6449     SPR_push + 3,                       1,
6450     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
6451   },
6452   {
6453     SPR_spray + 0,                      1,
6454     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
6455   },
6456   {
6457     SPR_spray + 1,                      1,
6458     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6459   },
6460   {
6461     SPR_spray + 2,                      1,
6462     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
6463   },
6464   {
6465     SPR_spray + 3,                      1,
6466     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
6467   },
6468   {
6469     SPR_still,                          0,
6470     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
6471   },
6472   {
6473     SPR_still,                          1,
6474     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
6475   },
6476   {
6477     SPR_walk + 0,                       2,
6478     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
6479   },
6480   {
6481     SPR_walk + 1,                       2,
6482     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
6483   },
6484   {
6485     SPR_walk + 2,                       2,
6486     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
6487   },
6488   {
6489     SPR_walk + 3,                       2,
6490     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
6491   },
6492   {
6493     SPR_push + 0,                       2,
6494     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
6495   },
6496   {
6497     SPR_push + 1,                       2,
6498     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
6499   },
6500   {
6501     SPR_push + 2,                       2,
6502     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
6503   },
6504   {
6505     SPR_push + 3,                       2,
6506     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
6507   },
6508   {
6509     SPR_spray + 0,                      2,
6510     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
6511   },
6512   {
6513     SPR_spray + 1,                      2,
6514     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6515   },
6516   {
6517     SPR_spray + 2,                      2,
6518     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
6519   },
6520   {
6521     SPR_spray + 3,                      2,
6522     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
6523   },
6524   {
6525     SPR_walk + 0,                       3,
6526     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
6527   },
6528   {
6529     SPR_walk + 1,                       3,
6530     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
6531   },
6532   {
6533     SPR_walk + 2,                       3,
6534     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
6535   },
6536   {
6537     SPR_walk + 3,                       3,
6538     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
6539   },
6540   {
6541     SPR_push + 0,                       3,
6542     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
6543   },
6544   {
6545     SPR_push + 1,                       3,
6546     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
6547   },
6548   {
6549     SPR_push + 2,                       3,
6550     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
6551   },
6552   {
6553     SPR_push + 3,                       3,
6554     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
6555   },
6556   {
6557     SPR_spray + 0,                      3,
6558     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
6559   },
6560   {
6561     SPR_spray + 1,                      3,
6562     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6563   },
6564   {
6565     SPR_spray + 2,                      3,
6566     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
6567   },
6568   {
6569     SPR_spray + 3,                      3,
6570     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
6571   },
6572   {
6573     SPR_still,                          2,
6574     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
6575   },
6576   {
6577     SPR_still,                          3,
6578     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
6579   },
6580
6581   {
6582     -1,                                 -1,
6583     -1,                                 -1, -1
6584   }
6585 };
6586
6587 int map_element_RND_to_EM(int element_rnd)
6588 {
6589   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6590   static boolean mapping_initialized = FALSE;
6591
6592   if (!mapping_initialized)
6593   {
6594     int i;
6595
6596     /* return "Xalpha_quest" for all undefined elements in mapping array */
6597     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6598       mapping_RND_to_EM[i] = Xalpha_quest;
6599
6600     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6601       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6602         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6603           em_object_mapping_list[i].element_em;
6604
6605     mapping_initialized = TRUE;
6606   }
6607
6608   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6609     return mapping_RND_to_EM[element_rnd];
6610
6611   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6612
6613   return EL_UNKNOWN;
6614 }
6615
6616 int map_element_EM_to_RND(int element_em)
6617 {
6618   static unsigned short mapping_EM_to_RND[TILE_MAX];
6619   static boolean mapping_initialized = FALSE;
6620
6621   if (!mapping_initialized)
6622   {
6623     int i;
6624
6625     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6626     for (i = 0; i < TILE_MAX; i++)
6627       mapping_EM_to_RND[i] = EL_UNKNOWN;
6628
6629     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6630       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6631         em_object_mapping_list[i].element_rnd;
6632
6633     mapping_initialized = TRUE;
6634   }
6635
6636   if (element_em >= 0 && element_em < TILE_MAX)
6637     return mapping_EM_to_RND[element_em];
6638
6639   Error(ERR_WARN, "invalid EM level element %d", element_em);
6640
6641   return EL_UNKNOWN;
6642 }
6643
6644 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6645 {
6646   struct LevelInfo_EM *level_em = level->native_em_level;
6647   struct LEVEL *lev = level_em->lev;
6648   int i, j;
6649
6650   for (i = 0; i < TILE_MAX; i++)
6651     lev->android_array[i] = Xblank;
6652
6653   for (i = 0; i < level->num_android_clone_elements; i++)
6654   {
6655     int element_rnd = level->android_clone_element[i];
6656     int element_em = map_element_RND_to_EM(element_rnd);
6657
6658     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6659       if (em_object_mapping_list[j].element_rnd == element_rnd)
6660         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6661   }
6662 }
6663
6664 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6665 {
6666   struct LevelInfo_EM *level_em = level->native_em_level;
6667   struct LEVEL *lev = level_em->lev;
6668   int i, j;
6669
6670   level->num_android_clone_elements = 0;
6671
6672   for (i = 0; i < TILE_MAX; i++)
6673   {
6674     int element_em = lev->android_array[i];
6675     int element_rnd;
6676     boolean element_found = FALSE;
6677
6678     if (element_em == Xblank)
6679       continue;
6680
6681     element_rnd = map_element_EM_to_RND(element_em);
6682
6683     for (j = 0; j < level->num_android_clone_elements; j++)
6684       if (level->android_clone_element[j] == element_rnd)
6685         element_found = TRUE;
6686
6687     if (!element_found)
6688     {
6689       level->android_clone_element[level->num_android_clone_elements++] =
6690         element_rnd;
6691
6692       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6693         break;
6694     }
6695   }
6696
6697   if (level->num_android_clone_elements == 0)
6698   {
6699     level->num_android_clone_elements = 1;
6700     level->android_clone_element[0] = EL_EMPTY;
6701   }
6702 }
6703
6704 int map_direction_RND_to_EM(int direction)
6705 {
6706   return (direction == MV_UP    ? 0 :
6707           direction == MV_RIGHT ? 1 :
6708           direction == MV_DOWN  ? 2 :
6709           direction == MV_LEFT  ? 3 :
6710           -1);
6711 }
6712
6713 int map_direction_EM_to_RND(int direction)
6714 {
6715   return (direction == 0 ? MV_UP    :
6716           direction == 1 ? MV_RIGHT :
6717           direction == 2 ? MV_DOWN  :
6718           direction == 3 ? MV_LEFT  :
6719           MV_NONE);
6720 }
6721
6722 int map_element_RND_to_SP(int element_rnd)
6723 {
6724   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
6725
6726   if (element_rnd >= EL_SP_START &&
6727       element_rnd <= EL_SP_END)
6728     element_sp = element_rnd - EL_SP_START;
6729   else if (element_rnd == EL_EMPTY_SPACE)
6730     element_sp = 0x00;
6731   else if (element_rnd == EL_INVISIBLE_WALL)
6732     element_sp = 0x28;
6733
6734   return element_sp;
6735 }
6736
6737 int map_element_SP_to_RND(int element_sp)
6738 {
6739   int element_rnd = EL_UNKNOWN;
6740
6741   if (element_sp >= 0x00 &&
6742       element_sp <= 0x27)
6743     element_rnd = EL_SP_START + element_sp;
6744   else if (element_sp == 0x28)
6745     element_rnd = EL_INVISIBLE_WALL;
6746
6747   return element_rnd;
6748 }
6749
6750 int map_action_SP_to_RND(int action_sp)
6751 {
6752   switch (action_sp)
6753   {
6754     case actActive:             return ACTION_ACTIVE;
6755     case actImpact:             return ACTION_IMPACT;
6756     case actExploding:          return ACTION_EXPLODING;
6757     case actDigging:            return ACTION_DIGGING;
6758     case actSnapping:           return ACTION_SNAPPING;
6759     case actCollecting:         return ACTION_COLLECTING;
6760     case actPassing:            return ACTION_PASSING;
6761     case actPushing:            return ACTION_PUSHING;
6762     case actDropping:           return ACTION_DROPPING;
6763
6764     default:                    return ACTION_DEFAULT;
6765   }
6766 }
6767
6768 int get_next_element(int element)
6769 {
6770   switch (element)
6771   {
6772     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
6773     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
6774     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
6775     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
6776     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
6777     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
6778     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
6779     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
6780     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
6781     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
6782     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
6783
6784     default:                            return element;
6785   }
6786 }
6787
6788 #if 0
6789 int el_act_dir2img(int element, int action, int direction)
6790 {
6791   element = GFX_ELEMENT(element);
6792
6793   if (direction == MV_NONE)
6794     return element_info[element].graphic[action];
6795
6796   direction = MV_DIR_TO_BIT(direction);
6797
6798   return element_info[element].direction_graphic[action][direction];
6799 }
6800 #else
6801 int el_act_dir2img(int element, int action, int direction)
6802 {
6803   element = GFX_ELEMENT(element);
6804   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6805
6806   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6807   return element_info[element].direction_graphic[action][direction];
6808 }
6809 #endif
6810
6811 #if 0
6812 static int el_act_dir2crm(int element, int action, int direction)
6813 {
6814   element = GFX_ELEMENT(element);
6815
6816   if (direction == MV_NONE)
6817     return element_info[element].crumbled[action];
6818
6819   direction = MV_DIR_TO_BIT(direction);
6820
6821   return element_info[element].direction_crumbled[action][direction];
6822 }
6823 #else
6824 static int el_act_dir2crm(int element, int action, int direction)
6825 {
6826   element = GFX_ELEMENT(element);
6827   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6828
6829   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6830   return element_info[element].direction_crumbled[action][direction];
6831 }
6832 #endif
6833
6834 int el_act2img(int element, int action)
6835 {
6836   element = GFX_ELEMENT(element);
6837
6838   return element_info[element].graphic[action];
6839 }
6840
6841 int el_act2crm(int element, int action)
6842 {
6843   element = GFX_ELEMENT(element);
6844
6845   return element_info[element].crumbled[action];
6846 }
6847
6848 int el_dir2img(int element, int direction)
6849 {
6850   element = GFX_ELEMENT(element);
6851
6852   return el_act_dir2img(element, ACTION_DEFAULT, direction);
6853 }
6854
6855 int el2baseimg(int element)
6856 {
6857   return element_info[element].graphic[ACTION_DEFAULT];
6858 }
6859
6860 int el2img(int element)
6861 {
6862   element = GFX_ELEMENT(element);
6863
6864   return element_info[element].graphic[ACTION_DEFAULT];
6865 }
6866
6867 int el2edimg(int element)
6868 {
6869   element = GFX_ELEMENT(element);
6870
6871   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6872 }
6873
6874 int el2preimg(int element)
6875 {
6876   element = GFX_ELEMENT(element);
6877
6878   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6879 }
6880
6881 int el2panelimg(int element)
6882 {
6883   element = GFX_ELEMENT(element);
6884
6885   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6886 }
6887
6888 int font2baseimg(int font_nr)
6889 {
6890   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6891 }
6892
6893 int getBeltNrFromBeltElement(int element)
6894 {
6895   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6896           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6897           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6898 }
6899
6900 int getBeltNrFromBeltActiveElement(int element)
6901 {
6902   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6903           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6904           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6905 }
6906
6907 int getBeltNrFromBeltSwitchElement(int element)
6908 {
6909   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6910           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6911           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6912 }
6913
6914 int getBeltDirNrFromBeltElement(int element)
6915 {
6916   static int belt_base_element[4] =
6917   {
6918     EL_CONVEYOR_BELT_1_LEFT,
6919     EL_CONVEYOR_BELT_2_LEFT,
6920     EL_CONVEYOR_BELT_3_LEFT,
6921     EL_CONVEYOR_BELT_4_LEFT
6922   };
6923
6924   int belt_nr = getBeltNrFromBeltElement(element);
6925   int belt_dir_nr = element - belt_base_element[belt_nr];
6926
6927   return (belt_dir_nr % 3);
6928 }
6929
6930 int getBeltDirNrFromBeltSwitchElement(int element)
6931 {
6932   static int belt_base_element[4] =
6933   {
6934     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6935     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6936     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6937     EL_CONVEYOR_BELT_4_SWITCH_LEFT
6938   };
6939
6940   int belt_nr = getBeltNrFromBeltSwitchElement(element);
6941   int belt_dir_nr = element - belt_base_element[belt_nr];
6942
6943   return (belt_dir_nr % 3);
6944 }
6945
6946 int getBeltDirFromBeltElement(int element)
6947 {
6948   static int belt_move_dir[3] =
6949   {
6950     MV_LEFT,
6951     MV_NONE,
6952     MV_RIGHT
6953   };
6954
6955   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6956
6957   return belt_move_dir[belt_dir_nr];
6958 }
6959
6960 int getBeltDirFromBeltSwitchElement(int element)
6961 {
6962   static int belt_move_dir[3] =
6963   {
6964     MV_LEFT,
6965     MV_NONE,
6966     MV_RIGHT
6967   };
6968
6969   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6970
6971   return belt_move_dir[belt_dir_nr];
6972 }
6973
6974 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6975 {
6976   static int belt_base_element[4] =
6977   {
6978     EL_CONVEYOR_BELT_1_LEFT,
6979     EL_CONVEYOR_BELT_2_LEFT,
6980     EL_CONVEYOR_BELT_3_LEFT,
6981     EL_CONVEYOR_BELT_4_LEFT
6982   };
6983
6984   return belt_base_element[belt_nr] + belt_dir_nr;
6985 }
6986
6987 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6988 {
6989   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6990
6991   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6992 }
6993
6994 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6995 {
6996   static int belt_base_element[4] =
6997   {
6998     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6999     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7000     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7001     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7002   };
7003
7004   return belt_base_element[belt_nr] + belt_dir_nr;
7005 }
7006
7007 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7008 {
7009   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7010
7011   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7012 }
7013
7014 int getNumActivePlayers_EM()
7015 {
7016   int num_players = 0;
7017   int i;
7018
7019   if (!tape.playing)
7020     return -1;
7021
7022   for (i = 0; i < MAX_PLAYERS; i++)
7023     if (tape.player_participates[i])
7024       num_players++;
7025
7026   return num_players;
7027 }
7028
7029 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7030 {
7031   int game_frame_delay_value;
7032
7033   game_frame_delay_value =
7034     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7035      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7036      GameFrameDelay);
7037
7038   if (tape.playing && tape.warp_forward && !tape.pausing)
7039     game_frame_delay_value = 0;
7040
7041   return game_frame_delay_value;
7042 }
7043
7044 unsigned int InitRND(long seed)
7045 {
7046   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7047     return InitEngineRandom_EM(seed);
7048   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7049     return InitEngineRandom_SP(seed);
7050   else
7051     return InitEngineRandom_RND(seed);
7052 }
7053
7054 #if 1
7055 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7056 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7057 #endif
7058
7059 inline static int get_effective_element_EM(int tile, int frame_em)
7060 {
7061   int element             = object_mapping[tile].element_rnd;
7062   int action              = object_mapping[tile].action;
7063   boolean is_backside     = object_mapping[tile].is_backside;
7064   boolean action_removing = (action == ACTION_DIGGING ||
7065                              action == ACTION_SNAPPING ||
7066                              action == ACTION_COLLECTING);
7067
7068   if (frame_em < 7)
7069   {
7070     switch (tile)
7071     {
7072       case Yacid_splash_eB:
7073       case Yacid_splash_wB:
7074         return (frame_em > 5 ? EL_EMPTY : element);
7075
7076 #if 0
7077       case Ydiamond_stone:
7078         //  if (!game.use_native_emc_graphics_engine)
7079         return EL_ROCK;
7080 #endif
7081
7082       default:
7083         return element;
7084     }
7085   }
7086   else  /* frame_em == 7 */
7087   {
7088     switch (tile)
7089     {
7090       case Yacid_splash_eB:
7091       case Yacid_splash_wB:
7092         return EL_EMPTY;
7093
7094       case Yemerald_stone:
7095         return EL_EMERALD;
7096
7097       case Ydiamond_stone:
7098         return EL_ROCK;
7099
7100       case Xdrip_stretch:
7101       case Xdrip_stretchB:
7102       case Ydrip_s1:
7103       case Ydrip_s1B:
7104       case Xball_1B:
7105       case Xball_2:
7106       case Xball_2B:
7107       case Yball_eat:
7108       case Ykey_1_eat:
7109       case Ykey_2_eat:
7110       case Ykey_3_eat:
7111       case Ykey_4_eat:
7112       case Ykey_5_eat:
7113       case Ykey_6_eat:
7114       case Ykey_7_eat:
7115       case Ykey_8_eat:
7116       case Ylenses_eat:
7117       case Ymagnify_eat:
7118       case Ygrass_eat:
7119       case Ydirt_eat:
7120       case Xsand_stonein_1:
7121       case Xsand_stonein_2:
7122       case Xsand_stonein_3:
7123       case Xsand_stonein_4:
7124         return element;
7125
7126       default:
7127         return (is_backside || action_removing ? EL_EMPTY : element);
7128     }
7129   }
7130 }
7131
7132 inline static boolean check_linear_animation_EM(int tile)
7133 {
7134   switch (tile)
7135   {
7136     case Xsand_stonesand_1:
7137     case Xsand_stonesand_quickout_1:
7138     case Xsand_sandstone_1:
7139     case Xsand_stonein_1:
7140     case Xsand_stoneout_1:
7141     case Xboom_1:
7142     case Xdynamite_1:
7143     case Ybug_w_n:
7144     case Ybug_n_e:
7145     case Ybug_e_s:
7146     case Ybug_s_w:
7147     case Ybug_e_n:
7148     case Ybug_s_e:
7149     case Ybug_w_s:
7150     case Ybug_n_w:
7151     case Ytank_w_n:
7152     case Ytank_n_e:
7153     case Ytank_e_s:
7154     case Ytank_s_w:
7155     case Ytank_e_n:
7156     case Ytank_s_e:
7157     case Ytank_w_s:
7158     case Ytank_n_w:
7159 #if 1
7160     case Yacid_splash_eB:
7161     case Yacid_splash_wB:
7162     case Yemerald_stone:
7163 #endif
7164       return TRUE;
7165   }
7166
7167   return FALSE;
7168 }
7169
7170 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7171                                             boolean has_crumbled_graphics,
7172                                             int crumbled, int sync_frame)
7173 {
7174   /* if element can be crumbled, but certain action graphics are just empty
7175      space (like instantly snapping sand to empty space in 1 frame), do not
7176      treat these empty space graphics as crumbled graphics in EMC engine */
7177   if (crumbled == IMG_EMPTY_SPACE)
7178     has_crumbled_graphics = FALSE;
7179
7180   if (has_crumbled_graphics)
7181   {
7182     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7183     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7184                                            g_crumbled->anim_delay,
7185                                            g_crumbled->anim_mode,
7186                                            g_crumbled->anim_start_frame,
7187                                            sync_frame);
7188
7189     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7190                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7191
7192     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7193
7194     g_em->has_crumbled_graphics = TRUE;
7195   }
7196   else
7197   {
7198     g_em->crumbled_bitmap = NULL;
7199     g_em->crumbled_src_x = 0;
7200     g_em->crumbled_src_y = 0;
7201     g_em->crumbled_border_size = 0;
7202
7203     g_em->has_crumbled_graphics = FALSE;
7204   }
7205 }
7206
7207 void ResetGfxAnimation_EM(int x, int y, int tile)
7208 {
7209   GfxFrame[x][y] = 0;
7210 }
7211
7212 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7213                         int tile, int frame_em, int x, int y)
7214 {
7215   int action = object_mapping[tile].action;
7216 #if 1
7217   int direction = object_mapping[tile].direction;
7218   int effective_element = get_effective_element_EM(tile, frame_em);
7219   int graphic = (direction == MV_NONE ?
7220                  el_act2img(effective_element, action) :
7221                  el_act_dir2img(effective_element, action, direction));
7222   struct GraphicInfo *g = &graphic_info[graphic];
7223   int sync_frame;
7224 #endif
7225   boolean action_removing = (action == ACTION_DIGGING ||
7226                              action == ACTION_SNAPPING ||
7227                              action == ACTION_COLLECTING);
7228   boolean action_moving   = (action == ACTION_FALLING ||
7229                              action == ACTION_MOVING ||
7230                              action == ACTION_PUSHING ||
7231                              action == ACTION_EATING ||
7232                              action == ACTION_FILLING ||
7233                              action == ACTION_EMPTYING);
7234   boolean action_falling  = (action == ACTION_FALLING ||
7235                              action == ACTION_FILLING ||
7236                              action == ACTION_EMPTYING);
7237
7238   /* special case: graphic uses "2nd movement tile" and has defined
7239      7 frames for movement animation (or less) => use default graphic
7240      for last (8th) frame which ends the movement animation */
7241   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7242   {
7243     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
7244     graphic = (direction == MV_NONE ?
7245                el_act2img(effective_element, action) :
7246                el_act_dir2img(effective_element, action, direction));
7247
7248     g = &graphic_info[graphic];
7249   }
7250
7251 #if 0
7252   if (tile == Xsand_stonesand_1 ||
7253       tile == Xsand_stonesand_2 ||
7254       tile == Xsand_stonesand_3 ||
7255       tile == Xsand_stonesand_4)
7256     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7257 #endif
7258
7259 #if 1
7260   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7261   {
7262     GfxFrame[x][y] = 0;
7263
7264     // printf("::: resetting... [%d]\n", tile);
7265   }
7266 #else
7267   if (action_removing || check_linear_animation_EM(tile))
7268   {
7269     GfxFrame[x][y] = frame_em;
7270
7271     // printf("::: resetting... [%d]\n", tile);
7272   }
7273 #endif
7274   else if (action_moving)
7275   {
7276     boolean is_backside = object_mapping[tile].is_backside;
7277
7278     if (is_backside)
7279     {
7280       int direction = object_mapping[tile].direction;
7281       int move_dir = (action_falling ? MV_DOWN : direction);
7282
7283       GfxFrame[x][y]++;
7284
7285 #if 1
7286       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7287       if (g->double_movement && frame_em == 0)
7288       {
7289         GfxFrame[x][y] = 0;
7290
7291         // printf("::: resetting... [%d]\n", tile);
7292       }
7293 #endif
7294
7295       if (move_dir == MV_LEFT)
7296         GfxFrame[x - 1][y] = GfxFrame[x][y];
7297       else if (move_dir == MV_RIGHT)
7298         GfxFrame[x + 1][y] = GfxFrame[x][y];
7299       else if (move_dir == MV_UP)
7300         GfxFrame[x][y - 1] = GfxFrame[x][y];
7301       else if (move_dir == MV_DOWN)
7302         GfxFrame[x][y + 1] = GfxFrame[x][y];
7303     }
7304   }
7305   else
7306   {
7307     GfxFrame[x][y]++;
7308
7309     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7310     if (tile == Xsand_stonesand_quickout_1 ||
7311         tile == Xsand_stonesand_quickout_2)
7312       GfxFrame[x][y]++;
7313   }
7314
7315 #if 0
7316   if (tile == Xsand_stonesand_1 ||
7317       tile == Xsand_stonesand_2 ||
7318       tile == Xsand_stonesand_3 ||
7319       tile == Xsand_stonesand_4)
7320     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7321 #endif
7322
7323 #if 1
7324   if (graphic_info[graphic].anim_global_sync)
7325     sync_frame = FrameCounter;
7326   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7327     sync_frame = GfxFrame[x][y];
7328   else
7329     sync_frame = 0;     /* playfield border (pseudo steel) */
7330
7331   SetRandomAnimationValue(x, y);
7332
7333   int frame = getAnimationFrame(g->anim_frames,
7334                                 g->anim_delay,
7335                                 g->anim_mode,
7336                                 g->anim_start_frame,
7337                                 sync_frame);
7338
7339   g_em->unique_identifier =
7340     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7341 #endif
7342 }
7343
7344 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7345                                   int tile, int frame_em, int x, int y)
7346 {
7347   int action = object_mapping[tile].action;
7348   int direction = object_mapping[tile].direction;
7349   boolean is_backside = object_mapping[tile].is_backside;
7350   int effective_element = get_effective_element_EM(tile, frame_em);
7351 #if 1
7352   int effective_action = action;
7353 #else
7354   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7355 #endif
7356   int graphic = (direction == MV_NONE ?
7357                  el_act2img(effective_element, effective_action) :
7358                  el_act_dir2img(effective_element, effective_action,
7359                                 direction));
7360   int crumbled = (direction == MV_NONE ?
7361                   el_act2crm(effective_element, effective_action) :
7362                   el_act_dir2crm(effective_element, effective_action,
7363                                  direction));
7364   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7365   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7366   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7367   struct GraphicInfo *g = &graphic_info[graphic];
7368 #if 0
7369   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7370 #endif
7371   int sync_frame;
7372
7373   /* special case: graphic uses "2nd movement tile" and has defined
7374      7 frames for movement animation (or less) => use default graphic
7375      for last (8th) frame which ends the movement animation */
7376   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7377   {
7378     effective_action = ACTION_DEFAULT;
7379     graphic = (direction == MV_NONE ?
7380                el_act2img(effective_element, effective_action) :
7381                el_act_dir2img(effective_element, effective_action,
7382                               direction));
7383     crumbled = (direction == MV_NONE ?
7384                 el_act2crm(effective_element, effective_action) :
7385                 el_act_dir2crm(effective_element, effective_action,
7386                                direction));
7387
7388     g = &graphic_info[graphic];
7389   }
7390
7391 #if 0
7392   if (frame_em == 7)
7393     return;
7394 #endif
7395
7396
7397 #if 0
7398   if (frame_em == 0)    /* reset animation frame for certain elements */
7399   {
7400     if (check_linear_animation_EM(tile))
7401       GfxFrame[x][y] = 0;
7402   }
7403 #endif
7404
7405   if (graphic_info[graphic].anim_global_sync)
7406     sync_frame = FrameCounter;
7407   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7408     sync_frame = GfxFrame[x][y];
7409   else
7410     sync_frame = 0;     /* playfield border (pseudo steel) */
7411
7412   SetRandomAnimationValue(x, y);
7413
7414 #if 0
7415   int i = tile;
7416   int j = frame_em;
7417   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7418                         i == Xdrip_stretchB ? 7 :
7419                         i == Ydrip_s2 ? j + 8 :
7420                         i == Ydrip_s2B ? j + 8 :
7421                         i == Xacid_1 ? 0 :
7422                         i == Xacid_2 ? 10 :
7423                         i == Xacid_3 ? 20 :
7424                         i == Xacid_4 ? 30 :
7425                         i == Xacid_5 ? 40 :
7426                         i == Xacid_6 ? 50 :
7427                         i == Xacid_7 ? 60 :
7428                         i == Xacid_8 ? 70 :
7429                         i == Xfake_acid_1 ? 0 :
7430                         i == Xfake_acid_2 ? 10 :
7431                         i == Xfake_acid_3 ? 20 :
7432                         i == Xfake_acid_4 ? 30 :
7433                         i == Xfake_acid_5 ? 40 :
7434                         i == Xfake_acid_6 ? 50 :
7435                         i == Xfake_acid_7 ? 60 :
7436                         i == Xfake_acid_8 ? 70 :
7437                         i == Xball_2 ? 7 :
7438                         i == Xball_2B ? j + 8 :
7439                         i == Yball_eat ? j + 1 :
7440                         i == Ykey_1_eat ? j + 1 :
7441                         i == Ykey_2_eat ? j + 1 :
7442                         i == Ykey_3_eat ? j + 1 :
7443                         i == Ykey_4_eat ? j + 1 :
7444                         i == Ykey_5_eat ? j + 1 :
7445                         i == Ykey_6_eat ? j + 1 :
7446                         i == Ykey_7_eat ? j + 1 :
7447                         i == Ykey_8_eat ? j + 1 :
7448                         i == Ylenses_eat ? j + 1 :
7449                         i == Ymagnify_eat ? j + 1 :
7450                         i == Ygrass_eat ? j + 1 :
7451                         i == Ydirt_eat ? j + 1 :
7452                         i == Xamoeba_1 ? 0 :
7453                         i == Xamoeba_2 ? 1 :
7454                         i == Xamoeba_3 ? 2 :
7455                         i == Xamoeba_4 ? 3 :
7456                         i == Xamoeba_5 ? 0 :
7457                         i == Xamoeba_6 ? 1 :
7458                         i == Xamoeba_7 ? 2 :
7459                         i == Xamoeba_8 ? 3 :
7460                         i == Xexit_2 ? j + 8 :
7461                         i == Xexit_3 ? j + 16 :
7462                         i == Xdynamite_1 ? 0 :
7463                         i == Xdynamite_2 ? 8 :
7464                         i == Xdynamite_3 ? 16 :
7465                         i == Xdynamite_4 ? 24 :
7466                         i == Xsand_stonein_1 ? j + 1 :
7467                         i == Xsand_stonein_2 ? j + 9 :
7468                         i == Xsand_stonein_3 ? j + 17 :
7469                         i == Xsand_stonein_4 ? j + 25 :
7470                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7471                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7472                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7473                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7474                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7475                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7476                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7477                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7478                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7479                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7480                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7481                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7482                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7483                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7484                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7485                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7486                         i == Xboom_bug && j == 1 ? 2 :
7487                         i == Xboom_bug && j == 2 ? 2 :
7488                         i == Xboom_bug && j == 3 ? 4 :
7489                         i == Xboom_bug && j == 4 ? 4 :
7490                         i == Xboom_bug && j == 5 ? 2 :
7491                         i == Xboom_bug && j == 6 ? 2 :
7492                         i == Xboom_bug && j == 7 ? 0 :
7493                         i == Xboom_bomb && j == 1 ? 2 :
7494                         i == Xboom_bomb && j == 2 ? 2 :
7495                         i == Xboom_bomb && j == 3 ? 4 :
7496                         i == Xboom_bomb && j == 4 ? 4 :
7497                         i == Xboom_bomb && j == 5 ? 2 :
7498                         i == Xboom_bomb && j == 6 ? 2 :
7499                         i == Xboom_bomb && j == 7 ? 0 :
7500                         i == Xboom_android && j == 7 ? 6 :
7501                         i == Xboom_1 && j == 1 ? 2 :
7502                         i == Xboom_1 && j == 2 ? 2 :
7503                         i == Xboom_1 && j == 3 ? 4 :
7504                         i == Xboom_1 && j == 4 ? 4 :
7505                         i == Xboom_1 && j == 5 ? 6 :
7506                         i == Xboom_1 && j == 6 ? 6 :
7507                         i == Xboom_1 && j == 7 ? 8 :
7508                         i == Xboom_2 && j == 0 ? 8 :
7509                         i == Xboom_2 && j == 1 ? 8 :
7510                         i == Xboom_2 && j == 2 ? 10 :
7511                         i == Xboom_2 && j == 3 ? 10 :
7512                         i == Xboom_2 && j == 4 ? 10 :
7513                         i == Xboom_2 && j == 5 ? 12 :
7514                         i == Xboom_2 && j == 6 ? 12 :
7515                         i == Xboom_2 && j == 7 ? 12 :
7516 #if 0
7517                         special_animation && j == 4 ? 3 :
7518                         effective_action != action ? 0 :
7519 #endif
7520                         j);
7521 #endif
7522
7523 #if 0
7524   int xxx_effective_action;
7525   int xxx_has_action_graphics;
7526
7527   {
7528     int element = object_mapping[i].element_rnd;
7529     int action = object_mapping[i].action;
7530     int direction = object_mapping[i].direction;
7531     boolean is_backside = object_mapping[i].is_backside;
7532 #if 0
7533     boolean action_removing = (action == ACTION_DIGGING ||
7534                                action == ACTION_SNAPPING ||
7535                                action == ACTION_COLLECTING);
7536 #endif
7537     boolean action_exploding = ((action == ACTION_EXPLODING ||
7538                                  action == ACTION_SMASHED_BY_ROCK ||
7539                                  action == ACTION_SMASHED_BY_SPRING) &&
7540                                 element != EL_DIAMOND);
7541     boolean action_active = (action == ACTION_ACTIVE);
7542     boolean action_other = (action == ACTION_OTHER);
7543
7544     {
7545 #if 1
7546       int effective_element = get_effective_element_EM(i, j);
7547 #else
7548       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7549                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7550                                j < 7 ? element :
7551                                i == Xdrip_stretch ? element :
7552                                i == Xdrip_stretchB ? element :
7553                                i == Ydrip_s1 ? element :
7554                                i == Ydrip_s1B ? element :
7555                                i == Xball_1B ? element :
7556                                i == Xball_2 ? element :
7557                                i == Xball_2B ? element :
7558                                i == Yball_eat ? element :
7559                                i == Ykey_1_eat ? element :
7560                                i == Ykey_2_eat ? element :
7561                                i == Ykey_3_eat ? element :
7562                                i == Ykey_4_eat ? element :
7563                                i == Ykey_5_eat ? element :
7564                                i == Ykey_6_eat ? element :
7565                                i == Ykey_7_eat ? element :
7566                                i == Ykey_8_eat ? element :
7567                                i == Ylenses_eat ? element :
7568                                i == Ymagnify_eat ? element :
7569                                i == Ygrass_eat ? element :
7570                                i == Ydirt_eat ? element :
7571                                i == Yemerald_stone ? EL_EMERALD :
7572                                i == Ydiamond_stone ? EL_ROCK :
7573                                i == Xsand_stonein_1 ? element :
7574                                i == Xsand_stonein_2 ? element :
7575                                i == Xsand_stonein_3 ? element :
7576                                i == Xsand_stonein_4 ? element :
7577                                is_backside ? EL_EMPTY :
7578                                action_removing ? EL_EMPTY :
7579                                element);
7580 #endif
7581       int effective_action = (j < 7 ? action :
7582                               i == Xdrip_stretch ? action :
7583                               i == Xdrip_stretchB ? action :
7584                               i == Ydrip_s1 ? action :
7585                               i == Ydrip_s1B ? action :
7586                               i == Xball_1B ? action :
7587                               i == Xball_2 ? action :
7588                               i == Xball_2B ? action :
7589                               i == Yball_eat ? action :
7590                               i == Ykey_1_eat ? action :
7591                               i == Ykey_2_eat ? action :
7592                               i == Ykey_3_eat ? action :
7593                               i == Ykey_4_eat ? action :
7594                               i == Ykey_5_eat ? action :
7595                               i == Ykey_6_eat ? action :
7596                               i == Ykey_7_eat ? action :
7597                               i == Ykey_8_eat ? action :
7598                               i == Ylenses_eat ? action :
7599                               i == Ymagnify_eat ? action :
7600                               i == Ygrass_eat ? action :
7601                               i == Ydirt_eat ? action :
7602                               i == Xsand_stonein_1 ? action :
7603                               i == Xsand_stonein_2 ? action :
7604                               i == Xsand_stonein_3 ? action :
7605                               i == Xsand_stonein_4 ? action :
7606                               i == Xsand_stoneout_1 ? action :
7607                               i == Xsand_stoneout_2 ? action :
7608                               i == Xboom_android ? ACTION_EXPLODING :
7609                               action_exploding ? ACTION_EXPLODING :
7610                               action_active ? action :
7611                               action_other ? action :
7612                               ACTION_DEFAULT);
7613       int graphic = (el_act_dir2img(effective_element, effective_action,
7614                                     direction));
7615       int crumbled = (el_act_dir2crm(effective_element, effective_action,
7616                                      direction));
7617       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7618       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7619       boolean has_action_graphics = (graphic != base_graphic);
7620       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7621       struct GraphicInfo *g = &graphic_info[graphic];
7622 #if 0
7623       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7624 #endif
7625       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7626       Bitmap *src_bitmap;
7627       int src_x, src_y;
7628       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7629       boolean special_animation = (action != ACTION_DEFAULT &&
7630                                    g->anim_frames == 3 &&
7631                                    g->anim_delay == 2 &&
7632                                    g->anim_mode & ANIM_LINEAR);
7633       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7634                         i == Xdrip_stretchB ? 7 :
7635                         i == Ydrip_s2 ? j + 8 :
7636                         i == Ydrip_s2B ? j + 8 :
7637                         i == Xacid_1 ? 0 :
7638                         i == Xacid_2 ? 10 :
7639                         i == Xacid_3 ? 20 :
7640                         i == Xacid_4 ? 30 :
7641                         i == Xacid_5 ? 40 :
7642                         i == Xacid_6 ? 50 :
7643                         i == Xacid_7 ? 60 :
7644                         i == Xacid_8 ? 70 :
7645                         i == Xfake_acid_1 ? 0 :
7646                         i == Xfake_acid_2 ? 10 :
7647                         i == Xfake_acid_3 ? 20 :
7648                         i == Xfake_acid_4 ? 30 :
7649                         i == Xfake_acid_5 ? 40 :
7650                         i == Xfake_acid_6 ? 50 :
7651                         i == Xfake_acid_7 ? 60 :
7652                         i == Xfake_acid_8 ? 70 :
7653                         i == Xball_2 ? 7 :
7654                         i == Xball_2B ? j + 8 :
7655                         i == Yball_eat ? j + 1 :
7656                         i == Ykey_1_eat ? j + 1 :
7657                         i == Ykey_2_eat ? j + 1 :
7658                         i == Ykey_3_eat ? j + 1 :
7659                         i == Ykey_4_eat ? j + 1 :
7660                         i == Ykey_5_eat ? j + 1 :
7661                         i == Ykey_6_eat ? j + 1 :
7662                         i == Ykey_7_eat ? j + 1 :
7663                         i == Ykey_8_eat ? j + 1 :
7664                         i == Ylenses_eat ? j + 1 :
7665                         i == Ymagnify_eat ? j + 1 :
7666                         i == Ygrass_eat ? j + 1 :
7667                         i == Ydirt_eat ? j + 1 :
7668                         i == Xamoeba_1 ? 0 :
7669                         i == Xamoeba_2 ? 1 :
7670                         i == Xamoeba_3 ? 2 :
7671                         i == Xamoeba_4 ? 3 :
7672                         i == Xamoeba_5 ? 0 :
7673                         i == Xamoeba_6 ? 1 :
7674                         i == Xamoeba_7 ? 2 :
7675                         i == Xamoeba_8 ? 3 :
7676                         i == Xexit_2 ? j + 8 :
7677                         i == Xexit_3 ? j + 16 :
7678                         i == Xdynamite_1 ? 0 :
7679                         i == Xdynamite_2 ? 8 :
7680                         i == Xdynamite_3 ? 16 :
7681                         i == Xdynamite_4 ? 24 :
7682                         i == Xsand_stonein_1 ? j + 1 :
7683                         i == Xsand_stonein_2 ? j + 9 :
7684                         i == Xsand_stonein_3 ? j + 17 :
7685                         i == Xsand_stonein_4 ? j + 25 :
7686                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7687                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7688                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7689                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7690                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7691                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7692                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7693                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7694                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7695                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7696                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7697                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7698                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7699                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7700                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7701                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7702                         i == Xboom_bug && j == 1 ? 2 :
7703                         i == Xboom_bug && j == 2 ? 2 :
7704                         i == Xboom_bug && j == 3 ? 4 :
7705                         i == Xboom_bug && j == 4 ? 4 :
7706                         i == Xboom_bug && j == 5 ? 2 :
7707                         i == Xboom_bug && j == 6 ? 2 :
7708                         i == Xboom_bug && j == 7 ? 0 :
7709                         i == Xboom_bomb && j == 1 ? 2 :
7710                         i == Xboom_bomb && j == 2 ? 2 :
7711                         i == Xboom_bomb && j == 3 ? 4 :
7712                         i == Xboom_bomb && j == 4 ? 4 :
7713                         i == Xboom_bomb && j == 5 ? 2 :
7714                         i == Xboom_bomb && j == 6 ? 2 :
7715                         i == Xboom_bomb && j == 7 ? 0 :
7716                         i == Xboom_android && j == 7 ? 6 :
7717                         i == Xboom_1 && j == 1 ? 2 :
7718                         i == Xboom_1 && j == 2 ? 2 :
7719                         i == Xboom_1 && j == 3 ? 4 :
7720                         i == Xboom_1 && j == 4 ? 4 :
7721                         i == Xboom_1 && j == 5 ? 6 :
7722                         i == Xboom_1 && j == 6 ? 6 :
7723                         i == Xboom_1 && j == 7 ? 8 :
7724                         i == Xboom_2 && j == 0 ? 8 :
7725                         i == Xboom_2 && j == 1 ? 8 :
7726                         i == Xboom_2 && j == 2 ? 10 :
7727                         i == Xboom_2 && j == 3 ? 10 :
7728                         i == Xboom_2 && j == 4 ? 10 :
7729                         i == Xboom_2 && j == 5 ? 12 :
7730                         i == Xboom_2 && j == 6 ? 12 :
7731                         i == Xboom_2 && j == 7 ? 12 :
7732                         special_animation && j == 4 ? 3 :
7733                         effective_action != action ? 0 :
7734                         j);
7735
7736       xxx_effective_action = effective_action;
7737       xxx_has_action_graphics = has_action_graphics;
7738     }
7739   }
7740 #endif
7741
7742   int frame = getAnimationFrame(g->anim_frames,
7743                                 g->anim_delay,
7744                                 g->anim_mode,
7745                                 g->anim_start_frame,
7746                                 sync_frame);
7747
7748
7749 #if 0
7750   return;
7751 #endif
7752
7753 #if 0
7754   if (frame_em == 7)
7755     return;
7756 #endif
7757
7758 #if 0
7759   int old_src_x = g_em->src_x;
7760   int old_src_y = g_em->src_y;
7761 #endif
7762
7763 #if 1
7764   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7765                       g->double_movement && is_backside);
7766 #else
7767   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7768                       &g_em->src_x, &g_em->src_y, FALSE);
7769 #endif
7770
7771
7772 #if 0
7773   if (tile == Ydiamond_stone)
7774     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
7775            frame_em,
7776            g->anim_frames,
7777            g->anim_delay,
7778            g->anim_mode,
7779            g->anim_start_frame,
7780            sync_frame,
7781            frame,
7782            g_em->src_x, g_em->src_y,
7783            g_em->src_offset_x, g_em->src_offset_y,
7784            g_em->dst_offset_x, g_em->dst_offset_y,
7785            graphic);
7786 #endif
7787
7788
7789 #if 0
7790   return;
7791 #endif
7792
7793 #if 0
7794   if (frame_em == 7)
7795   {
7796     if (graphic == IMG_BUG_MOVING_RIGHT)
7797       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
7798              g->double_movement, is_backside,
7799              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
7800
7801     return;
7802   }
7803 #endif
7804
7805
7806 #if 0
7807   g_em->src_offset_x = 0;
7808   g_em->src_offset_y = 0;
7809   g_em->dst_offset_x = 0;
7810   g_em->dst_offset_y = 0;
7811   g_em->width  = TILEX;
7812   g_em->height = TILEY;
7813
7814   g_em->preserve_background = FALSE;
7815 #endif
7816
7817   /* (updating the "crumbled" graphic definitions is probably not really needed,
7818      as animations for crumbled graphics can't be longer than one EMC cycle) */
7819 #if 1
7820   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7821                            sync_frame);
7822
7823 #else
7824
7825   g_em->crumbled_bitmap = NULL;
7826   g_em->crumbled_src_x = 0;
7827   g_em->crumbled_src_y = 0;
7828
7829   g_em->has_crumbled_graphics = FALSE;
7830
7831   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
7832   {
7833     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7834                                            g_crumbled->anim_delay,
7835                                            g_crumbled->anim_mode,
7836                                            g_crumbled->anim_start_frame,
7837                                            sync_frame);
7838
7839     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7840                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7841
7842     g_em->has_crumbled_graphics = TRUE;
7843   }
7844 #endif
7845
7846 #if 0
7847  {
7848    int effective_action = xxx_effective_action;
7849    int has_action_graphics = xxx_has_action_graphics;
7850
7851       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7852                                    effective_action == ACTION_MOVING  ||
7853                                    effective_action == ACTION_PUSHING ||
7854                                    effective_action == ACTION_EATING)) ||
7855           (!has_action_graphics && (effective_action == ACTION_FILLING ||
7856                                     effective_action == ACTION_EMPTYING)))
7857       {
7858         int move_dir =
7859           (effective_action == ACTION_FALLING ||
7860            effective_action == ACTION_FILLING ||
7861            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7862         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7863         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
7864         int num_steps = (i == Ydrip_s1  ? 16 :
7865                          i == Ydrip_s1B ? 16 :
7866                          i == Ydrip_s2  ? 16 :
7867                          i == Ydrip_s2B ? 16 :
7868                          i == Xsand_stonein_1 ? 32 :
7869                          i == Xsand_stonein_2 ? 32 :
7870                          i == Xsand_stonein_3 ? 32 :
7871                          i == Xsand_stonein_4 ? 32 :
7872                          i == Xsand_stoneout_1 ? 16 :
7873                          i == Xsand_stoneout_2 ? 16 : 8);
7874         int cx = ABS(dx) * (TILEX / num_steps);
7875         int cy = ABS(dy) * (TILEY / num_steps);
7876         int step_frame = (i == Ydrip_s2         ? j + 8 :
7877                           i == Ydrip_s2B        ? j + 8 :
7878                           i == Xsand_stonein_2  ? j + 8 :
7879                           i == Xsand_stonein_3  ? j + 16 :
7880                           i == Xsand_stonein_4  ? j + 24 :
7881                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7882         int step = (is_backside ? step_frame : num_steps - step_frame);
7883
7884         if (is_backside)        /* tile where movement starts */
7885         {
7886           if (dx < 0 || dy < 0)
7887           {
7888             g_em->src_offset_x = cx * step;
7889             g_em->src_offset_y = cy * step;
7890           }
7891           else
7892           {
7893             g_em->dst_offset_x = cx * step;
7894             g_em->dst_offset_y = cy * step;
7895           }
7896         }
7897         else                    /* tile where movement ends */
7898         {
7899           if (dx < 0 || dy < 0)
7900           {
7901             g_em->dst_offset_x = cx * step;
7902             g_em->dst_offset_y = cy * step;
7903           }
7904           else
7905           {
7906             g_em->src_offset_x = cx * step;
7907             g_em->src_offset_y = cy * step;
7908           }
7909         }
7910
7911         g_em->width  = TILEX - cx * step;
7912         g_em->height = TILEY - cy * step;
7913       }
7914
7915       /* create unique graphic identifier to decide if tile must be redrawn */
7916       /* bit 31 - 16 (16 bit): EM style graphic
7917          bit 15 - 12 ( 4 bit): EM style frame
7918          bit 11 -  6 ( 6 bit): graphic width
7919          bit  5 -  0 ( 6 bit): graphic height */
7920       g_em->unique_identifier =
7921         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7922  }
7923 #endif
7924
7925 }
7926
7927 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7928                                   int player_nr, int anim, int frame_em)
7929 {
7930   int element   = player_mapping[player_nr][anim].element_rnd;
7931   int action    = player_mapping[player_nr][anim].action;
7932   int direction = player_mapping[player_nr][anim].direction;
7933   int graphic = (direction == MV_NONE ?
7934                  el_act2img(element, action) :
7935                  el_act_dir2img(element, action, direction));
7936   struct GraphicInfo *g = &graphic_info[graphic];
7937   int sync_frame;
7938
7939   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7940
7941   stored_player[player_nr].StepFrame = frame_em;
7942
7943   sync_frame = stored_player[player_nr].Frame;
7944
7945   int frame = getAnimationFrame(g->anim_frames,
7946                                 g->anim_delay,
7947                                 g->anim_mode,
7948                                 g->anim_start_frame,
7949                                 sync_frame);
7950
7951   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7952                       &g_em->src_x, &g_em->src_y, FALSE);
7953
7954 #if 0
7955   printf("::: %d: %d, %d [%d]\n",
7956          player_nr,
7957          stored_player[player_nr].Frame,
7958          stored_player[player_nr].StepFrame,
7959          FrameCounter);
7960 #endif
7961 }
7962
7963 void InitGraphicInfo_EM(void)
7964 {
7965 #if 0
7966   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7967   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7968 #endif
7969   int i, j, p;
7970
7971 #if DEBUG_EM_GFX
7972   int num_em_gfx_errors = 0;
7973
7974   if (graphic_info_em_object[0][0].bitmap == NULL)
7975   {
7976     /* EM graphics not yet initialized in em_open_all() */
7977
7978     return;
7979   }
7980
7981   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7982 #endif
7983
7984   /* always start with reliable default values */
7985   for (i = 0; i < TILE_MAX; i++)
7986   {
7987     object_mapping[i].element_rnd = EL_UNKNOWN;
7988     object_mapping[i].is_backside = FALSE;
7989     object_mapping[i].action = ACTION_DEFAULT;
7990     object_mapping[i].direction = MV_NONE;
7991   }
7992
7993   /* always start with reliable default values */
7994   for (p = 0; p < MAX_PLAYERS; p++)
7995   {
7996     for (i = 0; i < SPR_MAX; i++)
7997     {
7998       player_mapping[p][i].element_rnd = EL_UNKNOWN;
7999       player_mapping[p][i].action = ACTION_DEFAULT;
8000       player_mapping[p][i].direction = MV_NONE;
8001     }
8002   }
8003
8004   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8005   {
8006     int e = em_object_mapping_list[i].element_em;
8007
8008     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8009     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8010
8011     if (em_object_mapping_list[i].action != -1)
8012       object_mapping[e].action = em_object_mapping_list[i].action;
8013
8014     if (em_object_mapping_list[i].direction != -1)
8015       object_mapping[e].direction =
8016         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8017   }
8018
8019   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8020   {
8021     int a = em_player_mapping_list[i].action_em;
8022     int p = em_player_mapping_list[i].player_nr;
8023
8024     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8025
8026     if (em_player_mapping_list[i].action != -1)
8027       player_mapping[p][a].action = em_player_mapping_list[i].action;
8028
8029     if (em_player_mapping_list[i].direction != -1)
8030       player_mapping[p][a].direction =
8031         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8032   }
8033
8034   for (i = 0; i < TILE_MAX; i++)
8035   {
8036     int element = object_mapping[i].element_rnd;
8037     int action = object_mapping[i].action;
8038     int direction = object_mapping[i].direction;
8039     boolean is_backside = object_mapping[i].is_backside;
8040 #if 0
8041     boolean action_removing = (action == ACTION_DIGGING ||
8042                                action == ACTION_SNAPPING ||
8043                                action == ACTION_COLLECTING);
8044 #endif
8045     boolean action_exploding = ((action == ACTION_EXPLODING ||
8046                                  action == ACTION_SMASHED_BY_ROCK ||
8047                                  action == ACTION_SMASHED_BY_SPRING) &&
8048                                 element != EL_DIAMOND);
8049     boolean action_active = (action == ACTION_ACTIVE);
8050     boolean action_other = (action == ACTION_OTHER);
8051
8052     for (j = 0; j < 8; j++)
8053     {
8054 #if 1
8055       int effective_element = get_effective_element_EM(i, j);
8056 #else
8057       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8058                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8059                                j < 7 ? element :
8060                                i == Xdrip_stretch ? element :
8061                                i == Xdrip_stretchB ? element :
8062                                i == Ydrip_s1 ? element :
8063                                i == Ydrip_s1B ? element :
8064                                i == Xball_1B ? element :
8065                                i == Xball_2 ? element :
8066                                i == Xball_2B ? element :
8067                                i == Yball_eat ? element :
8068                                i == Ykey_1_eat ? element :
8069                                i == Ykey_2_eat ? element :
8070                                i == Ykey_3_eat ? element :
8071                                i == Ykey_4_eat ? element :
8072                                i == Ykey_5_eat ? element :
8073                                i == Ykey_6_eat ? element :
8074                                i == Ykey_7_eat ? element :
8075                                i == Ykey_8_eat ? element :
8076                                i == Ylenses_eat ? element :
8077                                i == Ymagnify_eat ? element :
8078                                i == Ygrass_eat ? element :
8079                                i == Ydirt_eat ? element :
8080                                i == Yemerald_stone ? EL_EMERALD :
8081                                i == Ydiamond_stone ? EL_ROCK :
8082                                i == Xsand_stonein_1 ? element :
8083                                i == Xsand_stonein_2 ? element :
8084                                i == Xsand_stonein_3 ? element :
8085                                i == Xsand_stonein_4 ? element :
8086                                is_backside ? EL_EMPTY :
8087                                action_removing ? EL_EMPTY :
8088                                element);
8089 #endif
8090       int effective_action = (j < 7 ? action :
8091                               i == Xdrip_stretch ? action :
8092                               i == Xdrip_stretchB ? action :
8093                               i == Ydrip_s1 ? action :
8094                               i == Ydrip_s1B ? action :
8095                               i == Xball_1B ? action :
8096                               i == Xball_2 ? action :
8097                               i == Xball_2B ? action :
8098                               i == Yball_eat ? action :
8099                               i == Ykey_1_eat ? action :
8100                               i == Ykey_2_eat ? action :
8101                               i == Ykey_3_eat ? action :
8102                               i == Ykey_4_eat ? action :
8103                               i == Ykey_5_eat ? action :
8104                               i == Ykey_6_eat ? action :
8105                               i == Ykey_7_eat ? action :
8106                               i == Ykey_8_eat ? action :
8107                               i == Ylenses_eat ? action :
8108                               i == Ymagnify_eat ? action :
8109                               i == Ygrass_eat ? action :
8110                               i == Ydirt_eat ? action :
8111                               i == Xsand_stonein_1 ? action :
8112                               i == Xsand_stonein_2 ? action :
8113                               i == Xsand_stonein_3 ? action :
8114                               i == Xsand_stonein_4 ? action :
8115                               i == Xsand_stoneout_1 ? action :
8116                               i == Xsand_stoneout_2 ? action :
8117                               i == Xboom_android ? ACTION_EXPLODING :
8118                               action_exploding ? ACTION_EXPLODING :
8119                               action_active ? action :
8120                               action_other ? action :
8121                               ACTION_DEFAULT);
8122       int graphic = (el_act_dir2img(effective_element, effective_action,
8123                                     direction));
8124       int crumbled = (el_act_dir2crm(effective_element, effective_action,
8125                                      direction));
8126       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8127       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8128       boolean has_action_graphics = (graphic != base_graphic);
8129       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8130       struct GraphicInfo *g = &graphic_info[graphic];
8131 #if 0
8132       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8133 #endif
8134       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8135       Bitmap *src_bitmap;
8136       int src_x, src_y;
8137       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8138       boolean special_animation = (action != ACTION_DEFAULT &&
8139                                    g->anim_frames == 3 &&
8140                                    g->anim_delay == 2 &&
8141                                    g->anim_mode & ANIM_LINEAR);
8142       int sync_frame = (i == Xdrip_stretch ? 7 :
8143                         i == Xdrip_stretchB ? 7 :
8144                         i == Ydrip_s2 ? j + 8 :
8145                         i == Ydrip_s2B ? j + 8 :
8146                         i == Xacid_1 ? 0 :
8147                         i == Xacid_2 ? 10 :
8148                         i == Xacid_3 ? 20 :
8149                         i == Xacid_4 ? 30 :
8150                         i == Xacid_5 ? 40 :
8151                         i == Xacid_6 ? 50 :
8152                         i == Xacid_7 ? 60 :
8153                         i == Xacid_8 ? 70 :
8154                         i == Xfake_acid_1 ? 0 :
8155                         i == Xfake_acid_2 ? 10 :
8156                         i == Xfake_acid_3 ? 20 :
8157                         i == Xfake_acid_4 ? 30 :
8158                         i == Xfake_acid_5 ? 40 :
8159                         i == Xfake_acid_6 ? 50 :
8160                         i == Xfake_acid_7 ? 60 :
8161                         i == Xfake_acid_8 ? 70 :
8162                         i == Xball_2 ? 7 :
8163                         i == Xball_2B ? j + 8 :
8164                         i == Yball_eat ? j + 1 :
8165                         i == Ykey_1_eat ? j + 1 :
8166                         i == Ykey_2_eat ? j + 1 :
8167                         i == Ykey_3_eat ? j + 1 :
8168                         i == Ykey_4_eat ? j + 1 :
8169                         i == Ykey_5_eat ? j + 1 :
8170                         i == Ykey_6_eat ? j + 1 :
8171                         i == Ykey_7_eat ? j + 1 :
8172                         i == Ykey_8_eat ? j + 1 :
8173                         i == Ylenses_eat ? j + 1 :
8174                         i == Ymagnify_eat ? j + 1 :
8175                         i == Ygrass_eat ? j + 1 :
8176                         i == Ydirt_eat ? j + 1 :
8177                         i == Xamoeba_1 ? 0 :
8178                         i == Xamoeba_2 ? 1 :
8179                         i == Xamoeba_3 ? 2 :
8180                         i == Xamoeba_4 ? 3 :
8181                         i == Xamoeba_5 ? 0 :
8182                         i == Xamoeba_6 ? 1 :
8183                         i == Xamoeba_7 ? 2 :
8184                         i == Xamoeba_8 ? 3 :
8185                         i == Xexit_2 ? j + 8 :
8186                         i == Xexit_3 ? j + 16 :
8187                         i == Xdynamite_1 ? 0 :
8188                         i == Xdynamite_2 ? 8 :
8189                         i == Xdynamite_3 ? 16 :
8190                         i == Xdynamite_4 ? 24 :
8191                         i == Xsand_stonein_1 ? j + 1 :
8192                         i == Xsand_stonein_2 ? j + 9 :
8193                         i == Xsand_stonein_3 ? j + 17 :
8194                         i == Xsand_stonein_4 ? j + 25 :
8195                         i == Xsand_stoneout_1 && j == 0 ? 0 :
8196                         i == Xsand_stoneout_1 && j == 1 ? 0 :
8197                         i == Xsand_stoneout_1 && j == 2 ? 1 :
8198                         i == Xsand_stoneout_1 && j == 3 ? 2 :
8199                         i == Xsand_stoneout_1 && j == 4 ? 2 :
8200                         i == Xsand_stoneout_1 && j == 5 ? 3 :
8201                         i == Xsand_stoneout_1 && j == 6 ? 4 :
8202                         i == Xsand_stoneout_1 && j == 7 ? 4 :
8203                         i == Xsand_stoneout_2 && j == 0 ? 5 :
8204                         i == Xsand_stoneout_2 && j == 1 ? 6 :
8205                         i == Xsand_stoneout_2 && j == 2 ? 7 :
8206                         i == Xsand_stoneout_2 && j == 3 ? 8 :
8207                         i == Xsand_stoneout_2 && j == 4 ? 9 :
8208                         i == Xsand_stoneout_2 && j == 5 ? 11 :
8209                         i == Xsand_stoneout_2 && j == 6 ? 13 :
8210                         i == Xsand_stoneout_2 && j == 7 ? 15 :
8211                         i == Xboom_bug && j == 1 ? 2 :
8212                         i == Xboom_bug && j == 2 ? 2 :
8213                         i == Xboom_bug && j == 3 ? 4 :
8214                         i == Xboom_bug && j == 4 ? 4 :
8215                         i == Xboom_bug && j == 5 ? 2 :
8216                         i == Xboom_bug && j == 6 ? 2 :
8217                         i == Xboom_bug && j == 7 ? 0 :
8218                         i == Xboom_bomb && j == 1 ? 2 :
8219                         i == Xboom_bomb && j == 2 ? 2 :
8220                         i == Xboom_bomb && j == 3 ? 4 :
8221                         i == Xboom_bomb && j == 4 ? 4 :
8222                         i == Xboom_bomb && j == 5 ? 2 :
8223                         i == Xboom_bomb && j == 6 ? 2 :
8224                         i == Xboom_bomb && j == 7 ? 0 :
8225                         i == Xboom_android && j == 7 ? 6 :
8226                         i == Xboom_1 && j == 1 ? 2 :
8227                         i == Xboom_1 && j == 2 ? 2 :
8228                         i == Xboom_1 && j == 3 ? 4 :
8229                         i == Xboom_1 && j == 4 ? 4 :
8230                         i == Xboom_1 && j == 5 ? 6 :
8231                         i == Xboom_1 && j == 6 ? 6 :
8232                         i == Xboom_1 && j == 7 ? 8 :
8233                         i == Xboom_2 && j == 0 ? 8 :
8234                         i == Xboom_2 && j == 1 ? 8 :
8235                         i == Xboom_2 && j == 2 ? 10 :
8236                         i == Xboom_2 && j == 3 ? 10 :
8237                         i == Xboom_2 && j == 4 ? 10 :
8238                         i == Xboom_2 && j == 5 ? 12 :
8239                         i == Xboom_2 && j == 6 ? 12 :
8240                         i == Xboom_2 && j == 7 ? 12 :
8241                         special_animation && j == 4 ? 3 :
8242                         effective_action != action ? 0 :
8243                         j);
8244
8245 #if DEBUG_EM_GFX
8246       Bitmap *debug_bitmap = g_em->bitmap;
8247       int debug_src_x = g_em->src_x;
8248       int debug_src_y = g_em->src_y;
8249 #endif
8250
8251       int frame = getAnimationFrame(g->anim_frames,
8252                                     g->anim_delay,
8253                                     g->anim_mode,
8254                                     g->anim_start_frame,
8255                                     sync_frame);
8256
8257       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8258                           g->double_movement && is_backside);
8259
8260       g_em->bitmap = src_bitmap;
8261       g_em->src_x = src_x;
8262       g_em->src_y = src_y;
8263       g_em->src_offset_x = 0;
8264       g_em->src_offset_y = 0;
8265       g_em->dst_offset_x = 0;
8266       g_em->dst_offset_y = 0;
8267       g_em->width  = TILEX;
8268       g_em->height = TILEY;
8269
8270       g_em->preserve_background = FALSE;
8271
8272 #if 1
8273       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8274                                sync_frame);
8275
8276 #else
8277
8278       g_em->crumbled_bitmap = NULL;
8279       g_em->crumbled_src_x = 0;
8280       g_em->crumbled_src_y = 0;
8281       g_em->crumbled_border_size = 0;
8282
8283       g_em->has_crumbled_graphics = FALSE;
8284
8285 #if 0
8286       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8287         printf("::: empty crumbled: %d [%s], %d, %d\n",
8288                effective_element, element_info[effective_element].token_name,
8289                effective_action, direction);
8290 #endif
8291
8292       /* if element can be crumbled, but certain action graphics are just empty
8293          space (like instantly snapping sand to empty space in 1 frame), do not
8294          treat these empty space graphics as crumbled graphics in EMC engine */
8295       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8296       {
8297         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8298                                                g_crumbled->anim_delay,
8299                                                g_crumbled->anim_mode,
8300                                                g_crumbled->anim_start_frame,
8301                                                sync_frame);
8302
8303         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8304
8305         g_em->has_crumbled_graphics = TRUE;
8306         g_em->crumbled_bitmap = src_bitmap;
8307         g_em->crumbled_src_x = src_x;
8308         g_em->crumbled_src_y = src_y;
8309         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8310
8311
8312 #if 0
8313         if (g_em == &graphic_info_em_object[207][0])
8314           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8315                  graphic_info_em_object[207][0].crumbled_src_x,
8316                  graphic_info_em_object[207][0].crumbled_src_y,
8317
8318                  crumbled, frame, src_x, src_y,
8319
8320                  g->anim_frames,
8321                  g->anim_delay,
8322                  g->anim_mode,
8323                  g->anim_start_frame,
8324                  sync_frame,
8325                  gfx.anim_random_frame,
8326                  frame);
8327 #endif
8328
8329 #if 0
8330         printf("::: EMC tile %d is crumbled\n", i);
8331 #endif
8332       }
8333 #endif
8334
8335 #if 0
8336       if (element == EL_ROCK &&
8337           effective_action == ACTION_FILLING)
8338         printf("::: has_action_graphics == %d\n", has_action_graphics);
8339 #endif
8340
8341       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8342                                    effective_action == ACTION_MOVING  ||
8343                                    effective_action == ACTION_PUSHING ||
8344                                    effective_action == ACTION_EATING)) ||
8345           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8346                                     effective_action == ACTION_EMPTYING)))
8347       {
8348         int move_dir =
8349           (effective_action == ACTION_FALLING ||
8350            effective_action == ACTION_FILLING ||
8351            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8352         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8353         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8354         int num_steps = (i == Ydrip_s1  ? 16 :
8355                          i == Ydrip_s1B ? 16 :
8356                          i == Ydrip_s2  ? 16 :
8357                          i == Ydrip_s2B ? 16 :
8358                          i == Xsand_stonein_1 ? 32 :
8359                          i == Xsand_stonein_2 ? 32 :
8360                          i == Xsand_stonein_3 ? 32 :
8361                          i == Xsand_stonein_4 ? 32 :
8362                          i == Xsand_stoneout_1 ? 16 :
8363                          i == Xsand_stoneout_2 ? 16 : 8);
8364         int cx = ABS(dx) * (TILEX / num_steps);
8365         int cy = ABS(dy) * (TILEY / num_steps);
8366         int step_frame = (i == Ydrip_s2         ? j + 8 :
8367                           i == Ydrip_s2B        ? j + 8 :
8368                           i == Xsand_stonein_2  ? j + 8 :
8369                           i == Xsand_stonein_3  ? j + 16 :
8370                           i == Xsand_stonein_4  ? j + 24 :
8371                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8372         int step = (is_backside ? step_frame : num_steps - step_frame);
8373
8374         if (is_backside)        /* tile where movement starts */
8375         {
8376           if (dx < 0 || dy < 0)
8377           {
8378             g_em->src_offset_x = cx * step;
8379             g_em->src_offset_y = cy * step;
8380           }
8381           else
8382           {
8383             g_em->dst_offset_x = cx * step;
8384             g_em->dst_offset_y = cy * step;
8385           }
8386         }
8387         else                    /* tile where movement ends */
8388         {
8389           if (dx < 0 || dy < 0)
8390           {
8391             g_em->dst_offset_x = cx * step;
8392             g_em->dst_offset_y = cy * step;
8393           }
8394           else
8395           {
8396             g_em->src_offset_x = cx * step;
8397             g_em->src_offset_y = cy * step;
8398           }
8399         }
8400
8401         g_em->width  = TILEX - cx * step;
8402         g_em->height = TILEY - cy * step;
8403       }
8404
8405       /* create unique graphic identifier to decide if tile must be redrawn */
8406       /* bit 31 - 16 (16 bit): EM style graphic
8407          bit 15 - 12 ( 4 bit): EM style frame
8408          bit 11 -  6 ( 6 bit): graphic width
8409          bit  5 -  0 ( 6 bit): graphic height */
8410       g_em->unique_identifier =
8411         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8412
8413 #if DEBUG_EM_GFX
8414
8415       /* skip check for EMC elements not contained in original EMC artwork */
8416       if (element == EL_EMC_FAKE_ACID)
8417         continue;
8418
8419       if (g_em->bitmap != debug_bitmap ||
8420           g_em->src_x != debug_src_x ||
8421           g_em->src_y != debug_src_y ||
8422           g_em->src_offset_x != 0 ||
8423           g_em->src_offset_y != 0 ||
8424           g_em->dst_offset_x != 0 ||
8425           g_em->dst_offset_y != 0 ||
8426           g_em->width != TILEX ||
8427           g_em->height != TILEY)
8428       {
8429         static int last_i = -1;
8430
8431         if (i != last_i)
8432         {
8433           printf("\n");
8434           last_i = i;
8435         }
8436
8437         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8438                i, element, element_info[element].token_name,
8439                element_action_info[effective_action].suffix, direction);
8440
8441         if (element != effective_element)
8442           printf(" [%d ('%s')]",
8443                  effective_element,
8444                  element_info[effective_element].token_name);
8445
8446         printf("\n");
8447
8448         if (g_em->bitmap != debug_bitmap)
8449           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8450                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8451
8452         if (g_em->src_x != debug_src_x ||
8453             g_em->src_y != debug_src_y)
8454           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8455                  j, (is_backside ? 'B' : 'F'),
8456                  g_em->src_x, g_em->src_y,
8457                  g_em->src_x / 32, g_em->src_y / 32,
8458                  debug_src_x, debug_src_y,
8459                  debug_src_x / 32, debug_src_y / 32);
8460
8461         if (g_em->src_offset_x != 0 ||
8462             g_em->src_offset_y != 0 ||
8463             g_em->dst_offset_x != 0 ||
8464             g_em->dst_offset_y != 0)
8465           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8466                  j, is_backside,
8467                  g_em->src_offset_x, g_em->src_offset_y,
8468                  g_em->dst_offset_x, g_em->dst_offset_y);
8469
8470         if (g_em->width != TILEX ||
8471             g_em->height != TILEY)
8472           printf("    %d (%d): size %d,%d should be %d,%d\n",
8473                  j, is_backside,
8474                  g_em->width, g_em->height, TILEX, TILEY);
8475
8476         num_em_gfx_errors++;
8477       }
8478 #endif
8479
8480     }
8481   }
8482
8483   for (i = 0; i < TILE_MAX; i++)
8484   {
8485     for (j = 0; j < 8; j++)
8486     {
8487       int element = object_mapping[i].element_rnd;
8488       int action = object_mapping[i].action;
8489       int direction = object_mapping[i].direction;
8490       boolean is_backside = object_mapping[i].is_backside;
8491       int graphic_action  = el_act_dir2img(element, action, direction);
8492       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8493
8494       if ((action == ACTION_SMASHED_BY_ROCK ||
8495            action == ACTION_SMASHED_BY_SPRING ||
8496            action == ACTION_EATING) &&
8497           graphic_action == graphic_default)
8498       {
8499         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
8500                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8501                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
8502                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8503                  Xspring);
8504
8505         /* no separate animation for "smashed by rock" -- use rock instead */
8506         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8507         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8508
8509         g_em->bitmap            = g_xx->bitmap;
8510         g_em->src_x             = g_xx->src_x;
8511         g_em->src_y             = g_xx->src_y;
8512         g_em->src_offset_x      = g_xx->src_offset_x;
8513         g_em->src_offset_y      = g_xx->src_offset_y;
8514         g_em->dst_offset_x      = g_xx->dst_offset_x;
8515         g_em->dst_offset_y      = g_xx->dst_offset_y;
8516         g_em->width             = g_xx->width;
8517         g_em->height            = g_xx->height;
8518         g_em->unique_identifier = g_xx->unique_identifier;
8519
8520         if (!is_backside)
8521           g_em->preserve_background = TRUE;
8522       }
8523     }
8524   }
8525
8526   for (p = 0; p < MAX_PLAYERS; p++)
8527   {
8528     for (i = 0; i < SPR_MAX; i++)
8529     {
8530       int element = player_mapping[p][i].element_rnd;
8531       int action = player_mapping[p][i].action;
8532       int direction = player_mapping[p][i].direction;
8533
8534       for (j = 0; j < 8; j++)
8535       {
8536         int effective_element = element;
8537         int effective_action = action;
8538         int graphic = (direction == MV_NONE ?
8539                        el_act2img(effective_element, effective_action) :
8540                        el_act_dir2img(effective_element, effective_action,
8541                                       direction));
8542         struct GraphicInfo *g = &graphic_info[graphic];
8543         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8544         Bitmap *src_bitmap;
8545         int src_x, src_y;
8546         int sync_frame = j;
8547
8548 #if DEBUG_EM_GFX
8549         Bitmap *debug_bitmap = g_em->bitmap;
8550         int debug_src_x = g_em->src_x;
8551         int debug_src_y = g_em->src_y;
8552 #endif
8553
8554         int frame = getAnimationFrame(g->anim_frames,
8555                                       g->anim_delay,
8556                                       g->anim_mode,
8557                                       g->anim_start_frame,
8558                                       sync_frame);
8559
8560         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8561
8562         g_em->bitmap = src_bitmap;
8563         g_em->src_x = src_x;
8564         g_em->src_y = src_y;
8565         g_em->src_offset_x = 0;
8566         g_em->src_offset_y = 0;
8567         g_em->dst_offset_x = 0;
8568         g_em->dst_offset_y = 0;
8569         g_em->width  = TILEX;
8570         g_em->height = TILEY;
8571
8572 #if DEBUG_EM_GFX
8573
8574         /* skip check for EMC elements not contained in original EMC artwork */
8575         if (element == EL_PLAYER_3 ||
8576             element == EL_PLAYER_4)
8577           continue;
8578
8579         if (g_em->bitmap != debug_bitmap ||
8580             g_em->src_x != debug_src_x ||
8581             g_em->src_y != debug_src_y)
8582         {
8583           static int last_i = -1;
8584
8585           if (i != last_i)
8586           {
8587             printf("\n");
8588             last_i = i;
8589           }
8590
8591           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8592                  p, i, element, element_info[element].token_name,
8593                  element_action_info[effective_action].suffix, direction);
8594
8595           if (element != effective_element)
8596             printf(" [%d ('%s')]",
8597                    effective_element,
8598                    element_info[effective_element].token_name);
8599
8600           printf("\n");
8601
8602           if (g_em->bitmap != debug_bitmap)
8603             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
8604                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
8605
8606           if (g_em->src_x != debug_src_x ||
8607               g_em->src_y != debug_src_y)
8608             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8609                    j,
8610                    g_em->src_x, g_em->src_y,
8611                    g_em->src_x / 32, g_em->src_y / 32,
8612                    debug_src_x, debug_src_y,
8613                    debug_src_x / 32, debug_src_y / 32);
8614
8615           num_em_gfx_errors++;
8616         }
8617 #endif
8618
8619       }
8620     }
8621   }
8622
8623 #if DEBUG_EM_GFX
8624   printf("\n");
8625   printf("::: [%d errors found]\n", num_em_gfx_errors);
8626
8627   exit(0);
8628 #endif
8629 }
8630
8631 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8632                             boolean any_player_moving,
8633                             boolean player_is_dropping)
8634 {
8635   int i;
8636
8637   if (tape.single_step && tape.recording && !tape.pausing)
8638   {
8639     boolean active_players = FALSE;
8640
8641     for (i = 0; i < MAX_PLAYERS; i++)
8642       if (action[i] != JOY_NO_ACTION)
8643         active_players = TRUE;
8644
8645     // if (frame == 0)
8646     if (frame == 0 && !player_is_dropping)
8647       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8648   }
8649 }
8650
8651 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8652                             boolean murphy_is_dropping)
8653 {
8654 #if 0
8655   printf("::: waiting: %d, dropping: %d\n",
8656          murphy_is_waiting, murphy_is_dropping);
8657 #endif
8658
8659   if (tape.single_step && tape.recording && !tape.pausing)
8660   {
8661     // if (murphy_is_waiting || murphy_is_dropping)
8662     if (murphy_is_waiting)
8663     {
8664 #if 0
8665       printf("::: murphy is waiting -> pause mode\n");
8666 #endif
8667
8668       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8669     }
8670   }
8671 }
8672
8673 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8674                          int graphic, int sync_frame, int x, int y)
8675 {
8676   int frame = getGraphicAnimationFrame(graphic, sync_frame);
8677
8678   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8679 }
8680
8681 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
8682 {
8683   return (IS_NEXT_FRAME(sync_frame, graphic));
8684 }
8685
8686 int getGraphicInfo_Delay(int graphic)
8687 {
8688   return graphic_info[graphic].anim_delay;
8689 }
8690
8691 void PlayMenuSoundExt(int sound)
8692 {
8693   if (sound == SND_UNDEFINED)
8694     return;
8695
8696   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8697       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8698     return;
8699
8700   if (IS_LOOP_SOUND(sound))
8701     PlaySoundLoop(sound);
8702   else
8703     PlaySound(sound);
8704 }
8705
8706 void PlayMenuSound()
8707 {
8708   PlayMenuSoundExt(menu.sound[game_status]);
8709 }
8710
8711 void PlayMenuSoundStereo(int sound, int stereo_position)
8712 {
8713   if (sound == SND_UNDEFINED)
8714     return;
8715
8716   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8717       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8718     return;
8719
8720   if (IS_LOOP_SOUND(sound))
8721     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
8722   else
8723     PlaySoundStereo(sound, stereo_position);
8724 }
8725
8726 void PlayMenuSoundIfLoopExt(int sound)
8727 {
8728   if (sound == SND_UNDEFINED)
8729     return;
8730
8731   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
8732       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
8733     return;
8734
8735   if (IS_LOOP_SOUND(sound))
8736     PlaySoundLoop(sound);
8737 }
8738
8739 void PlayMenuSoundIfLoop()
8740 {
8741   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
8742 }
8743
8744 void PlayMenuMusicExt(int music)
8745 {
8746   if (music == MUS_UNDEFINED)
8747     return;
8748
8749   if (!setup.sound_music)
8750     return;
8751
8752   PlayMusic(music);
8753 }
8754
8755 void PlayMenuMusic()
8756 {
8757   PlayMenuMusicExt(menu.music[game_status]);
8758 }
8759
8760 void PlaySoundActivating()
8761 {
8762 #if 0
8763   PlaySound(SND_MENU_ITEM_ACTIVATING);
8764 #endif
8765 }
8766
8767 void PlaySoundSelecting()
8768 {
8769 #if 0
8770   PlaySound(SND_MENU_ITEM_SELECTING);
8771 #endif
8772 }
8773
8774 void ToggleFullscreenIfNeeded()
8775 {
8776   boolean change_fullscreen = (setup.fullscreen !=
8777                                video.fullscreen_enabled);
8778   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
8779                                     !strEqual(setup.fullscreen_mode,
8780                                               video.fullscreen_mode_current));
8781
8782   if (!video.fullscreen_available)
8783     return;
8784
8785   if (change_fullscreen || change_fullscreen_mode)
8786   {
8787     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
8788
8789     /* save backbuffer content which gets lost when toggling fullscreen mode */
8790     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8791
8792     if (change_fullscreen_mode)
8793     {
8794       /* keep fullscreen, but change fullscreen mode (screen resolution) */
8795       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
8796     }
8797
8798     /* toggle fullscreen */
8799     ChangeVideoModeIfNeeded(setup.fullscreen);
8800
8801     setup.fullscreen = video.fullscreen_enabled;
8802
8803     /* restore backbuffer content from temporary backbuffer backup bitmap */
8804     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8805
8806     FreeBitmap(tmp_backbuffer);
8807
8808 #if 1
8809     /* update visible window/screen */
8810     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
8811 #else
8812     redraw_mask = REDRAW_ALL;
8813 #endif
8814   }
8815 }
8816
8817 void ChangeViewportPropertiesIfNeeded()
8818 {
8819   int *door_1_x = &DX;
8820   int *door_1_y = &DY;
8821   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
8822   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
8823   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
8824                        game_status == GAME_MODE_EDITOR ? game_status :
8825                        GAME_MODE_MAIN);
8826   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
8827   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
8828   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
8829   int border_size = vp_playfield->border_size;
8830   int new_sx = vp_playfield->x + border_size;
8831   int new_sy = vp_playfield->y + border_size;
8832   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? TILESIZE_VAR :
8833                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
8834   int new_sxsize = vp_playfield->width  - 2 * border_size;
8835   int new_sysize = vp_playfield->height - 2 * border_size;
8836 #if NEW_TILESIZE
8837   int new_scr_fieldx = new_sxsize / tilesize;
8838   int new_scr_fieldy = new_sysize / tilesize;
8839 #else
8840   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
8841   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
8842 #endif
8843
8844 #if 0
8845   /* !!! TEST ONLY !!! */
8846   // InitGfxBuffers();
8847   return;
8848 #endif
8849
8850   if (viewport.window.width  != WIN_XSIZE ||
8851       viewport.window.height != WIN_YSIZE)
8852   {
8853     WIN_XSIZE = viewport.window.width;
8854     WIN_YSIZE = viewport.window.height;
8855
8856     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8857     InitGfxBuffers();
8858
8859 #if 1
8860     SetDrawDeactivationMask(REDRAW_NONE);
8861     SetDrawBackgroundMask(REDRAW_FIELD);
8862
8863     // RedrawBackground();
8864 #endif
8865   }
8866
8867   if (new_scr_fieldx != SCR_FIELDX ||
8868       new_scr_fieldy != SCR_FIELDY ||
8869       new_sx != SX ||
8870       new_sy != SY ||
8871       vp_playfield->x != REAL_SX ||
8872       vp_playfield->y != REAL_SY ||
8873       vp_door_1->x != *door_1_x ||
8874       vp_door_1->y != *door_1_y ||
8875       vp_door_2->x != *door_2_x ||
8876       vp_door_2->y != *door_2_y)
8877   {
8878     SCR_FIELDX = new_scr_fieldx;
8879     SCR_FIELDY = new_scr_fieldy;
8880     SX = new_sx;
8881     SY = new_sy;
8882     REAL_SX = vp_playfield->x;
8883     REAL_SY = vp_playfield->y;
8884
8885     SXSIZE = new_sxsize;
8886     SYSIZE = new_sysize;
8887     FULL_SXSIZE = vp_playfield->width;
8888     FULL_SYSIZE = vp_playfield->width;
8889
8890     *door_1_x = vp_door_1->x;
8891     *door_1_y = vp_door_1->y;
8892     *door_2_x = vp_door_2->x;
8893     *door_2_y = vp_door_2->y;
8894
8895     InitGfxBuffers();
8896
8897     if (gfx_game_mode == GAME_MODE_MAIN)
8898     {
8899       InitGadgets();
8900       InitToons();
8901     }
8902   }
8903
8904 #if 0
8905   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
8906 #endif
8907 }