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