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