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