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