rnd-20140114-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 #if 1
2545     BlitScreenToBitmap(backbuffer);
2546 #else
2547     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2548 #endif
2549
2550     SetDrawtoField(DRAW_BACKBUFFER);
2551
2552     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2553       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2554
2555 #if 1
2556     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2557                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2558                    xsize - 2, ysize - 2, 0, mask_mode,
2559                    level.envelope[envelope_nr].autowrap,
2560                    level.envelope[envelope_nr].centered, FALSE);
2561 #else
2562     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2563                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2564                        xsize - 2, ysize - 2, mask_mode);
2565 #endif
2566
2567     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2568     BackToFront();
2569
2570     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2571   }
2572 }
2573
2574 void AnimateEnvelopeDoor(char *text, int anim_mode, int action)
2575 {
2576 #if 1
2577   int envelope_nr = 0;
2578 #endif
2579   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2580   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2581   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2582   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2583   boolean no_delay = (tape.warp_forward);
2584   unsigned int anim_delay = 0;
2585   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2586   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2587 #if 1
2588   int max_word_len = maxWordLengthInString(text);
2589   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2590 #else
2591   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2592 #endif
2593   int font_width = getFontWidth(font_nr);
2594   int font_height = getFontHeight(font_nr);
2595 #if 1
2596
2597 #if 1
2598   int max_xsize = DXSIZE / font_width;
2599   int max_ysize = DYSIZE / font_height;
2600 #else
2601   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2602   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
2603 #endif
2604
2605 #else
2606   int max_xsize = level.envelope[envelope_nr].xsize;
2607   int max_ysize = level.envelope[envelope_nr].ysize;
2608 #endif
2609   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2610   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2611   int xend = max_xsize;
2612   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2613   int xstep = (xstart < xend ? 1 : 0);
2614   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2615   int x, y;
2616
2617 #if 1
2618   char *text_ptr;
2619   char *text_copy = getStringCopy(text);
2620 #else
2621 #if 1
2622   font_nr = FONT_TEXT_2;
2623
2624   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2625   {
2626     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2627     font_nr = FONT_TEXT_1;
2628   }
2629 #else
2630   int max_word_len = 0;
2631   char *text_ptr;
2632   char *text_copy = getStringCopy(text);
2633
2634   font_nr = FONT_TEXT_2;
2635
2636   for (text_ptr = text; *text_ptr; text_ptr++)
2637   {
2638     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2639
2640     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2641     {
2642       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2643       font_nr = FONT_TEXT_1;
2644
2645       break;
2646     }
2647   }
2648 #endif
2649 #endif
2650
2651 #if 1
2652   for (text_ptr = text_copy; *text_ptr; text_ptr++)
2653     if (*text_ptr == ' ')
2654       *text_ptr = '\n';
2655 #endif
2656
2657 #if 1
2658   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2659   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2660 #else
2661   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
2662   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2663 #endif
2664
2665   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2666   {
2667     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2668     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2669     int sx = (SXSIZE - xsize * font_width)  / 2;
2670     int sy = (SYSIZE - ysize * font_height) / 2;
2671     int xx, yy;
2672
2673 #if 1
2674     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2675 #else
2676     SetDrawtoField(DRAW_BUFFERED);
2677
2678 #if 1
2679     BlitScreenToBitmap(backbuffer);
2680 #else
2681     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2682 #endif
2683
2684     SetDrawtoField(DRAW_BACKBUFFER);
2685 #endif
2686
2687     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
2688       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
2689
2690 #if 1
2691
2692 #if 1
2693     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height + 8,
2694                    text_copy, font_nr, max_xsize,
2695                    xsize - 2, ysize - 2, 2, mask_mode,
2696                    FALSE, TRUE, FALSE);
2697 #else
2698     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
2699                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2700                    xsize - 2, ysize - 2, 0, mask_mode,
2701                    level.envelope[envelope_nr].autowrap,
2702                    level.envelope[envelope_nr].centered, FALSE);
2703 #endif
2704
2705 #else
2706     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
2707                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2708                        xsize - 2, ysize - 2, mask_mode);
2709 #endif
2710
2711     /* copy request gadgets to door backbuffer */
2712 #if 1
2713     if ((ysize - 2) > 13)
2714       BlitBitmap(bitmap_db_door, drawto,
2715                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2716                  DOOR_GFX_PAGEY1 + 13 * font_height,
2717                  (xsize - 2) * font_width,
2718                  (ysize - 2 - 13) * font_height,
2719                  SX + sx + font_width,
2720                  SY + sy + font_height * (1 + 13));
2721 #else
2722     if ((ysize - 2) > 13)
2723       BlitBitmap(bitmap_db_door, drawto,
2724                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2725                  DOOR_GFX_PAGEY1 + 13 * font_height,
2726                  (xsize - 2) * font_width,
2727                  (ysize - 2 - 13) * font_height,
2728                  SX + sx + font_width,
2729                  SY + sy + font_height * (1 + 13));
2730 #endif
2731
2732 #if 1
2733     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2734     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2735 #else
2736     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2737 #endif
2738
2739 #if 1
2740     DoAnimation();
2741     BackToFront();
2742 #else
2743     BackToFront();
2744 #endif
2745
2746     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2747   }
2748
2749 #if 1
2750   free(text_copy);
2751 #endif
2752 }
2753
2754 void ShowEnvelope(int envelope_nr)
2755 {
2756   int element = EL_ENVELOPE_1 + envelope_nr;
2757   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2758   int sound_opening = element_info[element].sound[ACTION_OPENING];
2759   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2760   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2761   boolean no_delay = (tape.warp_forward);
2762   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2763   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2764   int anim_mode = graphic_info[graphic].anim_mode;
2765   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2766                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2767
2768   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2769
2770   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2771
2772   if (anim_mode == ANIM_DEFAULT)
2773     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2774
2775   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2776
2777   if (tape.playing)
2778     Delay(wait_delay_value);
2779   else
2780     WaitForEventToContinue();
2781
2782   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2783
2784   if (anim_mode != ANIM_NONE)
2785     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2786
2787   if (anim_mode == ANIM_DEFAULT)
2788     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2789
2790   game.envelope_active = FALSE;
2791
2792   SetDrawtoField(DRAW_BUFFERED);
2793
2794   redraw_mask |= REDRAW_FIELD;
2795   BackToFront();
2796 }
2797
2798 void ShowEnvelopeDoor(char *text, int action)
2799 {
2800 #if 1
2801   int last_game_status = game_status;   /* save current game status */
2802   // int last_draw_background_mask = gfx.draw_background_mask;
2803   int envelope_nr = 0;
2804 #endif
2805   int element = EL_ENVELOPE_1 + envelope_nr;
2806   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2807   int sound_opening = element_info[element].sound[ACTION_OPENING];
2808   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2809 #if 0
2810   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2811   boolean no_delay = (tape.warp_forward);
2812   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2813   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2814 #endif
2815   int anim_mode = graphic_info[graphic].anim_mode;
2816   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2817                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2818
2819 #if 1
2820   if (game_status == GAME_MODE_PLAYING)
2821   {
2822     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
2823       BlitScreenToBitmap_EM(backbuffer);
2824     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
2825       BlitScreenToBitmap_SP(backbuffer);
2826     else
2827     {
2828       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2829     }
2830   }
2831
2832   SetDrawtoField(DRAW_BACKBUFFER);
2833
2834   // SetDrawBackgroundMask(REDRAW_NONE);
2835
2836   if (action == ACTION_OPENING)
2837   {
2838     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2839
2840     if (game_status != GAME_MODE_MAIN)
2841       InitAnimation();
2842   }
2843
2844   /* force DOOR font inside door area */
2845   game_status = GAME_MODE_PSEUDO_DOOR;
2846 #endif
2847
2848   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2849
2850   if (action == ACTION_OPENING)
2851   {
2852     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2853
2854     if (anim_mode == ANIM_DEFAULT)
2855       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_OPENING);
2856
2857     AnimateEnvelopeDoor(text, main_anim_mode, ACTION_OPENING);
2858
2859 #if 0
2860     if (tape.playing)
2861       Delay(wait_delay_value);
2862     else
2863       WaitForEventToContinue();
2864 #endif
2865   }
2866   else
2867   {
2868     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2869
2870     if (anim_mode != ANIM_NONE)
2871       AnimateEnvelopeDoor(text, main_anim_mode, ACTION_CLOSING);
2872
2873     if (anim_mode == ANIM_DEFAULT)
2874       AnimateEnvelopeDoor(text, ANIM_DEFAULT, ACTION_CLOSING);
2875   }
2876
2877   game.envelope_active = FALSE;
2878
2879 #if 1
2880   // game_status = last_game_status;    /* restore current game status */
2881
2882   if (action == ACTION_CLOSING)
2883   {
2884     if (game_status != GAME_MODE_MAIN)
2885       StopAnimation();
2886
2887     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2888   }
2889 #else
2890   SetDrawtoField(DRAW_BUFFERED);
2891 #endif
2892
2893   // SetDrawBackgroundMask(last_draw_background_mask);
2894
2895 #if 1
2896   redraw_mask = REDRAW_FIELD;
2897   // redraw_mask |= REDRAW_ALL;
2898 #else
2899   redraw_mask |= REDRAW_FIELD;
2900 #endif
2901
2902 #if 1
2903   if (game_status == GAME_MODE_MAIN)
2904     DoAnimation();
2905
2906   BackToFront();
2907
2908   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
2909   game_status = last_game_status;       /* restore current game status */
2910
2911   if (game_status == GAME_MODE_PLAYING &&
2912       level.game_engine_type == GAME_ENGINE_TYPE_RND)
2913     SetDrawtoField(DRAW_BUFFERED);
2914 #else
2915   BackToFront();
2916 #endif
2917 }
2918
2919 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2920 {
2921   Bitmap *src_bitmap;
2922   int src_x, src_y;
2923   int graphic = el2preimg(element);
2924
2925   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2926   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2927 }
2928
2929 void DrawLevel()
2930 {
2931   int x,y;
2932
2933 #if 1
2934   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2935   SetDrawBackgroundMask(REDRAW_FIELD);
2936 #else
2937   SetDrawBackgroundMask(REDRAW_NONE);
2938 #endif
2939
2940   ClearField();
2941
2942   for (x = BX1; x <= BX2; x++)
2943     for (y = BY1; y <= BY2; y++)
2944       DrawScreenField(x, y);
2945
2946   redraw_mask |= REDRAW_FIELD;
2947 }
2948
2949 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2950 {
2951   int x,y;
2952
2953   for (x = 0; x < size_x; x++)
2954     for (y = 0; y < size_y; y++)
2955       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2956
2957   redraw_mask |= REDRAW_FIELD;
2958 }
2959
2960 static void DrawPreviewLevelExt(int from_x, int from_y)
2961 {
2962   boolean show_level_border = (BorderElement != EL_EMPTY);
2963   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2964   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2965   int tile_size = preview.tile_size;
2966   int preview_width  = preview.xsize * tile_size;
2967   int preview_height = preview.ysize * tile_size;
2968   int real_preview_xsize = MIN(level_xsize, preview.xsize);
2969   int real_preview_ysize = MIN(level_ysize, preview.ysize);
2970   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2971   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2972   int x, y;
2973
2974   DrawBackground(dst_x, dst_y, preview_width, preview_height);
2975
2976   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
2977   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2978
2979   for (x = 0; x < real_preview_xsize; x++)
2980   {
2981     for (y = 0; y < real_preview_ysize; y++)
2982     {
2983       int lx = from_x + x + (show_level_border ? -1 : 0);
2984       int ly = from_y + y + (show_level_border ? -1 : 0);
2985       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2986                      getBorderElement(lx, ly));
2987
2988       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2989                          element, tile_size);
2990     }
2991   }
2992
2993   redraw_mask |= REDRAW_MICROLEVEL;
2994 }
2995
2996 #define MICROLABEL_EMPTY                0
2997 #define MICROLABEL_LEVEL_NAME           1
2998 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
2999 #define MICROLABEL_LEVEL_AUTHOR         3
3000 #define MICROLABEL_IMPORTED_FROM_HEAD   4
3001 #define MICROLABEL_IMPORTED_FROM        5
3002 #define MICROLABEL_IMPORTED_BY_HEAD     6
3003 #define MICROLABEL_IMPORTED_BY          7
3004
3005 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3006 {
3007   int max_text_width = SXSIZE;
3008   int font_width = getFontWidth(font_nr);
3009
3010   if (pos->align == ALIGN_CENTER)
3011     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3012   else if (pos->align == ALIGN_RIGHT)
3013     max_text_width = pos->x;
3014   else
3015     max_text_width = SXSIZE - pos->x;
3016
3017   return max_text_width / font_width;
3018 }
3019
3020 static void DrawPreviewLevelLabelExt(int mode)
3021 {
3022   struct TextPosInfo *pos = &menu.main.text.level_info_2;
3023   char label_text[MAX_OUTPUT_LINESIZE + 1];
3024   int max_len_label_text;
3025 #if 1
3026   int font_nr = pos->font;
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 = pos->font_alt;
3033 #else
3034   int font_nr = FONT_TEXT_2;
3035   int i;
3036
3037   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3038       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3039       mode == MICROLABEL_IMPORTED_BY_HEAD)
3040     font_nr = FONT_TEXT_3;
3041 #endif
3042
3043 #if 1
3044   max_len_label_text = getMaxTextLength(pos, font_nr);
3045 #else
3046   max_len_label_text = SXSIZE / getFontWidth(font_nr);
3047 #endif
3048
3049 #if 1
3050   if (pos->size != -1)
3051     max_len_label_text = pos->size;
3052 #endif
3053
3054   for (i = 0; i < max_len_label_text; i++)
3055     label_text[i] = ' ';
3056   label_text[max_len_label_text] = '\0';
3057
3058   if (strlen(label_text) > 0)
3059   {
3060 #if 1
3061     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3062 #else
3063     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3064     int lypos = MICROLABEL2_YPOS;
3065
3066     DrawText(lxpos, lypos, label_text, font_nr);
3067 #endif
3068   }
3069
3070   strncpy(label_text,
3071           (mode == MICROLABEL_LEVEL_NAME ? level.name :
3072            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3073            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3074            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3075            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3076            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3077            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3078           max_len_label_text);
3079   label_text[max_len_label_text] = '\0';
3080
3081   if (strlen(label_text) > 0)
3082   {
3083 #if 1
3084     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3085 #else
3086     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3087     int lypos = MICROLABEL2_YPOS;
3088
3089     DrawText(lxpos, lypos, label_text, font_nr);
3090 #endif
3091   }
3092
3093   redraw_mask |= REDRAW_MICROLEVEL;
3094 }
3095
3096 void DrawPreviewLevel(boolean restart)
3097 {
3098   static unsigned int scroll_delay = 0;
3099   static unsigned int label_delay = 0;
3100   static int from_x, from_y, scroll_direction;
3101   static int label_state, label_counter;
3102   unsigned int scroll_delay_value = preview.step_delay;
3103   boolean show_level_border = (BorderElement != EL_EMPTY);
3104   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3105   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3106   int last_game_status = game_status;           /* save current game status */
3107
3108 #if 0
3109   /* force PREVIEW font on preview level */
3110   game_status = GAME_MODE_PSEUDO_PREVIEW;
3111 #endif
3112
3113   if (restart)
3114   {
3115     from_x = 0;
3116     from_y = 0;
3117
3118     if (preview.anim_mode == ANIM_CENTERED)
3119     {
3120       if (level_xsize > preview.xsize)
3121         from_x = (level_xsize - preview.xsize) / 2;
3122       if (level_ysize > preview.ysize)
3123         from_y = (level_ysize - preview.ysize) / 2;
3124     }
3125
3126     from_x += preview.xoffset;
3127     from_y += preview.yoffset;
3128
3129     scroll_direction = MV_RIGHT;
3130     label_state = 1;
3131     label_counter = 0;
3132
3133     DrawPreviewLevelExt(from_x, from_y);
3134     DrawPreviewLevelLabelExt(label_state);
3135
3136     /* initialize delay counters */
3137     DelayReached(&scroll_delay, 0);
3138     DelayReached(&label_delay, 0);
3139
3140     if (leveldir_current->name)
3141     {
3142       struct TextPosInfo *pos = &menu.main.text.level_info_1;
3143       char label_text[MAX_OUTPUT_LINESIZE + 1];
3144 #if 1
3145       int font_nr = pos->font;
3146 #else
3147       int font_nr = FONT_TEXT_1;
3148 #endif
3149 #if 1
3150       int max_len_label_text = getMaxTextLength(pos, font_nr);
3151 #else
3152       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3153 #endif
3154 #if 0
3155       int text_width;
3156       int lxpos, lypos;
3157 #endif
3158
3159 #if 1
3160       if (pos->size != -1)
3161         max_len_label_text = pos->size;
3162 #endif
3163
3164       strncpy(label_text, leveldir_current->name, max_len_label_text);
3165       label_text[max_len_label_text] = '\0';
3166
3167 #if 1
3168       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3169 #else
3170       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3171       lypos = SY + MICROLABEL1_YPOS;
3172
3173       DrawText(lxpos, lypos, label_text, font_nr);
3174 #endif
3175     }
3176
3177     game_status = last_game_status;     /* restore current game status */
3178
3179     return;
3180   }
3181
3182   /* scroll preview level, if needed */
3183   if (preview.anim_mode != ANIM_NONE &&
3184       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3185       DelayReached(&scroll_delay, scroll_delay_value))
3186   {
3187     switch (scroll_direction)
3188     {
3189       case MV_LEFT:
3190         if (from_x > 0)
3191         {
3192           from_x -= preview.step_offset;
3193           from_x = (from_x < 0 ? 0 : from_x);
3194         }
3195         else
3196           scroll_direction = MV_UP;
3197         break;
3198
3199       case MV_RIGHT:
3200         if (from_x < level_xsize - preview.xsize)
3201         {
3202           from_x += preview.step_offset;
3203           from_x = (from_x > level_xsize - preview.xsize ?
3204                     level_xsize - preview.xsize : from_x);
3205         }
3206         else
3207           scroll_direction = MV_DOWN;
3208         break;
3209
3210       case MV_UP:
3211         if (from_y > 0)
3212         {
3213           from_y -= preview.step_offset;
3214           from_y = (from_y < 0 ? 0 : from_y);
3215         }
3216         else
3217           scroll_direction = MV_RIGHT;
3218         break;
3219
3220       case MV_DOWN:
3221         if (from_y < level_ysize - preview.ysize)
3222         {
3223           from_y += preview.step_offset;
3224           from_y = (from_y > level_ysize - preview.ysize ?
3225                     level_ysize - preview.ysize : from_y);
3226         }
3227         else
3228           scroll_direction = MV_LEFT;
3229         break;
3230
3231       default:
3232         break;
3233     }
3234
3235     DrawPreviewLevelExt(from_x, from_y);
3236   }
3237
3238   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3239   /* redraw micro level label, if needed */
3240   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3241       !strEqual(level.author, ANONYMOUS_NAME) &&
3242       !strEqual(level.author, leveldir_current->name) &&
3243       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3244   {
3245     int max_label_counter = 23;
3246
3247     if (leveldir_current->imported_from != NULL &&
3248         strlen(leveldir_current->imported_from) > 0)
3249       max_label_counter += 14;
3250     if (leveldir_current->imported_by != NULL &&
3251         strlen(leveldir_current->imported_by) > 0)
3252       max_label_counter += 14;
3253
3254     label_counter = (label_counter + 1) % max_label_counter;
3255     label_state = (label_counter >= 0 && label_counter <= 7 ?
3256                    MICROLABEL_LEVEL_NAME :
3257                    label_counter >= 9 && label_counter <= 12 ?
3258                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3259                    label_counter >= 14 && label_counter <= 21 ?
3260                    MICROLABEL_LEVEL_AUTHOR :
3261                    label_counter >= 23 && label_counter <= 26 ?
3262                    MICROLABEL_IMPORTED_FROM_HEAD :
3263                    label_counter >= 28 && label_counter <= 35 ?
3264                    MICROLABEL_IMPORTED_FROM :
3265                    label_counter >= 37 && label_counter <= 40 ?
3266                    MICROLABEL_IMPORTED_BY_HEAD :
3267                    label_counter >= 42 && label_counter <= 49 ?
3268                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3269
3270     if (leveldir_current->imported_from == NULL &&
3271         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3272          label_state == MICROLABEL_IMPORTED_FROM))
3273       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3274                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3275
3276     DrawPreviewLevelLabelExt(label_state);
3277   }
3278
3279   game_status = last_game_status;       /* restore current game status */
3280 }
3281
3282 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3283                                     int graphic, int sync_frame, int mask_mode)
3284 {
3285   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3286
3287   if (mask_mode == USE_MASKING)
3288     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3289   else
3290     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3291 }
3292
3293 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3294                                          int graphic, int sync_frame,
3295                                          int mask_mode)
3296 {
3297   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3298
3299   if (mask_mode == USE_MASKING)
3300     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3301   else
3302     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3303 }
3304
3305 inline void DrawGraphicAnimation(int x, int y, int graphic)
3306 {
3307   int lx = LEVELX(x), ly = LEVELY(y);
3308
3309   if (!IN_SCR_FIELD(x, y))
3310     return;
3311
3312 #if NEW_TILESIZE
3313   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3314                           graphic, GfxFrame[lx][ly], NO_MASKING);
3315 #else
3316   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3317                           graphic, GfxFrame[lx][ly], NO_MASKING);
3318 #endif
3319   MarkTileDirty(x, y);
3320 }
3321
3322 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3323 {
3324   int lx = LEVELX(x), ly = LEVELY(y);
3325
3326   if (!IN_SCR_FIELD(x, y))
3327     return;
3328
3329   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3330                           graphic, GfxFrame[lx][ly], NO_MASKING);
3331   MarkTileDirty(x, y);
3332 }
3333
3334 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3335 {
3336   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3337 }
3338
3339 void DrawLevelElementAnimation(int x, int y, int element)
3340 {
3341   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3342
3343   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3344 }
3345
3346 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3347 {
3348   int sx = SCREENX(x), sy = SCREENY(y);
3349
3350   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3351     return;
3352
3353   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3354     return;
3355
3356   DrawGraphicAnimation(sx, sy, graphic);
3357
3358 #if 1
3359   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3360     DrawLevelFieldCrumbled(x, y);
3361 #else
3362   if (GFX_CRUMBLED(Feld[x][y]))
3363     DrawLevelFieldCrumbled(x, y);
3364 #endif
3365 }
3366
3367 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3368 {
3369   int sx = SCREENX(x), sy = SCREENY(y);
3370   int graphic;
3371
3372   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3373     return;
3374
3375   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3376
3377   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3378     return;
3379
3380   DrawGraphicAnimation(sx, sy, graphic);
3381
3382   if (GFX_CRUMBLED(element))
3383     DrawLevelFieldCrumbled(x, y);
3384 }
3385
3386 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3387 {
3388   if (player->use_murphy)
3389   {
3390     /* this works only because currently only one player can be "murphy" ... */
3391     static int last_horizontal_dir = MV_LEFT;
3392     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3393
3394     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3395       last_horizontal_dir = move_dir;
3396
3397     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
3398     {
3399       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3400
3401       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3402     }
3403
3404     return graphic;
3405   }
3406   else
3407     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3408 }
3409
3410 static boolean equalGraphics(int graphic1, int graphic2)
3411 {
3412   struct GraphicInfo *g1 = &graphic_info[graphic1];
3413   struct GraphicInfo *g2 = &graphic_info[graphic2];
3414
3415   return (g1->bitmap      == g2->bitmap &&
3416           g1->src_x       == g2->src_x &&
3417           g1->src_y       == g2->src_y &&
3418           g1->anim_frames == g2->anim_frames &&
3419           g1->anim_delay  == g2->anim_delay &&
3420           g1->anim_mode   == g2->anim_mode);
3421 }
3422
3423 void DrawAllPlayers()
3424 {
3425   int i;
3426
3427   for (i = 0; i < MAX_PLAYERS; i++)
3428     if (stored_player[i].active)
3429       DrawPlayer(&stored_player[i]);
3430 }
3431
3432 void DrawPlayerField(int x, int y)
3433 {
3434   if (!IS_PLAYER(x, y))
3435     return;
3436
3437   DrawPlayer(PLAYERINFO(x, y));
3438 }
3439
3440 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3441
3442 void DrawPlayer(struct PlayerInfo *player)
3443 {
3444   int jx = player->jx;
3445   int jy = player->jy;
3446   int move_dir = player->MovDir;
3447   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3448   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
3449   int last_jx = (player->is_moving ? jx - dx : jx);
3450   int last_jy = (player->is_moving ? jy - dy : jy);
3451   int next_jx = jx + dx;
3452   int next_jy = jy + dy;
3453   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3454   boolean player_is_opaque = FALSE;
3455   int sx = SCREENX(jx), sy = SCREENY(jy);
3456   int sxx = 0, syy = 0;
3457   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3458   int graphic;
3459   int action = ACTION_DEFAULT;
3460   int last_player_graphic = getPlayerGraphic(player, move_dir);
3461   int last_player_frame = player->Frame;
3462   int frame = 0;
3463
3464   /* GfxElement[][] is set to the element the player is digging or collecting;
3465      remove also for off-screen player if the player is not moving anymore */
3466   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3467     GfxElement[jx][jy] = EL_UNDEFINED;
3468
3469   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3470     return;
3471
3472 #if DEBUG
3473   if (!IN_LEV_FIELD(jx, jy))
3474   {
3475     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3476     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3477     printf("DrawPlayerField(): This should never happen!\n");
3478     return;
3479   }
3480 #endif
3481
3482   if (element == EL_EXPLOSION)
3483     return;
3484
3485   action = (player->is_pushing    ? ACTION_PUSHING         :
3486             player->is_digging    ? ACTION_DIGGING         :
3487             player->is_collecting ? ACTION_COLLECTING      :
3488             player->is_moving     ? ACTION_MOVING          :
3489             player->is_snapping   ? ACTION_SNAPPING        :
3490             player->is_dropping   ? ACTION_DROPPING        :
3491             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
3492
3493   if (player->is_waiting)
3494     move_dir = player->dir_waiting;
3495
3496   InitPlayerGfxAnimation(player, action, move_dir);
3497
3498   /* ----------------------------------------------------------------------- */
3499   /* draw things in the field the player is leaving, if needed               */
3500   /* ----------------------------------------------------------------------- */
3501
3502   if (player->is_moving)
3503   {
3504     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3505     {
3506       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3507
3508       if (last_element == EL_DYNAMITE_ACTIVE ||
3509           last_element == EL_EM_DYNAMITE_ACTIVE ||
3510           last_element == EL_SP_DISK_RED_ACTIVE)
3511         DrawDynamite(last_jx, last_jy);
3512       else
3513         DrawLevelFieldThruMask(last_jx, last_jy);
3514     }
3515     else if (last_element == EL_DYNAMITE_ACTIVE ||
3516              last_element == EL_EM_DYNAMITE_ACTIVE ||
3517              last_element == EL_SP_DISK_RED_ACTIVE)
3518       DrawDynamite(last_jx, last_jy);
3519 #if 0
3520     /* !!! this is not enough to prevent flickering of players which are
3521        moving next to each others without a free tile between them -- this
3522        can only be solved by drawing all players layer by layer (first the
3523        background, then the foreground etc.) !!! => TODO */
3524     else if (!IS_PLAYER(last_jx, last_jy))
3525       DrawLevelField(last_jx, last_jy);
3526 #else
3527     else
3528       DrawLevelField(last_jx, last_jy);
3529 #endif
3530
3531     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3532       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3533   }
3534
3535   if (!IN_SCR_FIELD(sx, sy))
3536     return;
3537
3538   /* ----------------------------------------------------------------------- */
3539   /* draw things behind the player, if needed                                */
3540   /* ----------------------------------------------------------------------- */
3541
3542   if (Back[jx][jy])
3543     DrawLevelElement(jx, jy, Back[jx][jy]);
3544   else if (IS_ACTIVE_BOMB(element))
3545     DrawLevelElement(jx, jy, EL_EMPTY);
3546   else
3547   {
3548     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3549     {
3550       int old_element = GfxElement[jx][jy];
3551       int old_graphic = el_act_dir2img(old_element, action, move_dir);
3552       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3553
3554       if (GFX_CRUMBLED(old_element))
3555         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3556       else
3557         DrawGraphic(sx, sy, old_graphic, frame);
3558
3559       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3560         player_is_opaque = TRUE;
3561     }
3562     else
3563     {
3564       GfxElement[jx][jy] = EL_UNDEFINED;
3565
3566       /* make sure that pushed elements are drawn with correct frame rate */
3567 #if 1
3568       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3569
3570       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3571         GfxFrame[jx][jy] = player->StepFrame;
3572 #else
3573       if (player->is_pushing && player->is_moving)
3574         GfxFrame[jx][jy] = player->StepFrame;
3575 #endif
3576
3577       DrawLevelField(jx, jy);
3578     }
3579   }
3580
3581 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3582   /* ----------------------------------------------------------------------- */
3583   /* draw player himself                                                     */
3584   /* ----------------------------------------------------------------------- */
3585
3586   graphic = getPlayerGraphic(player, move_dir);
3587
3588   /* in the case of changed player action or direction, prevent the current
3589      animation frame from being restarted for identical animations */
3590   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3591     player->Frame = last_player_frame;
3592
3593   frame = getGraphicAnimationFrame(graphic, player->Frame);
3594
3595   if (player->GfxPos)
3596   {
3597     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3598       sxx = player->GfxPos;
3599     else
3600       syy = player->GfxPos;
3601   }
3602
3603   if (!setup.soft_scrolling && ScreenMovPos)
3604     sxx = syy = 0;
3605
3606   if (player_is_opaque)
3607     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3608   else
3609     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3610
3611   if (SHIELD_ON(player))
3612   {
3613     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3614                    IMG_SHIELD_NORMAL_ACTIVE);
3615     int frame = getGraphicAnimationFrame(graphic, -1);
3616
3617     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3618   }
3619 #endif
3620
3621 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3622   if (player->GfxPos)
3623   {
3624     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3625       sxx = player->GfxPos;
3626     else
3627       syy = player->GfxPos;
3628   }
3629 #endif
3630
3631   /* ----------------------------------------------------------------------- */
3632   /* draw things the player is pushing, if needed                            */
3633   /* ----------------------------------------------------------------------- */
3634
3635 #if 0
3636   printf("::: %d, %d [%d, %d] [%d]\n",
3637          player->is_pushing, player_is_moving, player->GfxAction,
3638          player->is_moving, player_is_moving);
3639 #endif
3640
3641 #if 1
3642   if (player->is_pushing && player->is_moving)
3643   {
3644     int px = SCREENX(jx), py = SCREENY(jy);
3645     int pxx = (TILEX - ABS(sxx)) * dx;
3646     int pyy = (TILEY - ABS(syy)) * dy;
3647     int gfx_frame = GfxFrame[jx][jy];
3648
3649     int graphic;
3650     int sync_frame;
3651     int frame;
3652
3653     if (!IS_MOVING(jx, jy))             /* push movement already finished */
3654     {
3655       element = Feld[next_jx][next_jy];
3656       gfx_frame = GfxFrame[next_jx][next_jy];
3657     }
3658
3659     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3660
3661 #if 1
3662     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3663     frame = getGraphicAnimationFrame(graphic, sync_frame);
3664 #else
3665     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3666 #endif
3667
3668     /* draw background element under pushed element (like the Sokoban field) */
3669 #if 1
3670     if (game.use_masked_pushing && IS_MOVING(jx, jy))
3671     {
3672       /* this allows transparent pushing animation over non-black background */
3673
3674       if (Back[jx][jy])
3675         DrawLevelElement(jx, jy, Back[jx][jy]);
3676       else
3677         DrawLevelElement(jx, jy, EL_EMPTY);
3678
3679       if (Back[next_jx][next_jy])
3680         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3681       else
3682         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3683     }
3684     else if (Back[next_jx][next_jy])
3685       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3686 #else
3687     if (Back[next_jx][next_jy])
3688       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3689 #endif
3690
3691 #if 0
3692     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3693            jx, px, player->GfxPos, player->StepFrame,
3694            player->is_pushing,
3695            dx, sxx, pxx,
3696            IS_MOVING(jx, jy),
3697            graphic, frame,
3698            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3699 #endif
3700
3701 #if 1
3702     /* do not draw (EM style) pushing animation when pushing is finished */
3703     /* (two-tile animations usually do not contain start and end frame) */
3704     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3705       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3706     else
3707       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3708 #else
3709     /* masked drawing is needed for EMC style (double) movement graphics */
3710     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3711     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3712 #endif
3713   }
3714 #endif
3715
3716 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3717   /* ----------------------------------------------------------------------- */
3718   /* draw player himself                                                     */
3719   /* ----------------------------------------------------------------------- */
3720
3721   graphic = getPlayerGraphic(player, move_dir);
3722
3723   /* in the case of changed player action or direction, prevent the current
3724      animation frame from being restarted for identical animations */
3725   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3726     player->Frame = last_player_frame;
3727
3728   frame = getGraphicAnimationFrame(graphic, player->Frame);
3729
3730   if (player->GfxPos)
3731   {
3732     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3733       sxx = player->GfxPos;
3734     else
3735       syy = player->GfxPos;
3736   }
3737
3738   if (!setup.soft_scrolling && ScreenMovPos)
3739     sxx = syy = 0;
3740
3741   if (player_is_opaque)
3742     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3743   else
3744     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3745
3746   if (SHIELD_ON(player))
3747   {
3748     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3749                    IMG_SHIELD_NORMAL_ACTIVE);
3750     int frame = getGraphicAnimationFrame(graphic, -1);
3751
3752     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3753   }
3754 #endif
3755
3756   /* ----------------------------------------------------------------------- */
3757   /* draw things in front of player (active dynamite or dynabombs)           */
3758   /* ----------------------------------------------------------------------- */
3759
3760   if (IS_ACTIVE_BOMB(element))
3761   {
3762     graphic = el2img(element);
3763     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3764
3765     if (game.emulation == EMU_SUPAPLEX)
3766       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3767     else
3768       DrawGraphicThruMask(sx, sy, graphic, frame);
3769   }
3770
3771   if (player_is_moving && last_element == EL_EXPLOSION)
3772   {
3773     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3774                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
3775     int graphic = el_act2img(element, ACTION_EXPLODING);
3776     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3777     int phase = ExplodePhase[last_jx][last_jy] - 1;
3778     int frame = getGraphicAnimationFrame(graphic, phase - delay);
3779
3780     if (phase >= delay)
3781       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3782   }
3783
3784   /* ----------------------------------------------------------------------- */
3785   /* draw elements the player is just walking/passing through/under          */
3786   /* ----------------------------------------------------------------------- */
3787
3788   if (player_is_moving)
3789   {
3790     /* handle the field the player is leaving ... */
3791     if (IS_ACCESSIBLE_INSIDE(last_element))
3792       DrawLevelField(last_jx, last_jy);
3793     else if (IS_ACCESSIBLE_UNDER(last_element))
3794       DrawLevelFieldThruMask(last_jx, last_jy);
3795   }
3796
3797   /* do not redraw accessible elements if the player is just pushing them */
3798   if (!player_is_moving || !player->is_pushing)
3799   {
3800     /* ... and the field the player is entering */
3801     if (IS_ACCESSIBLE_INSIDE(element))
3802       DrawLevelField(jx, jy);
3803     else if (IS_ACCESSIBLE_UNDER(element))
3804       DrawLevelFieldThruMask(jx, jy);
3805   }
3806
3807   MarkTileDirty(sx, sy);
3808 }
3809
3810 /* ------------------------------------------------------------------------- */
3811
3812 void WaitForEventToContinue()
3813 {
3814   boolean still_wait = TRUE;
3815
3816   /* simulate releasing mouse button over last gadget, if still pressed */
3817   if (button_status)
3818     HandleGadgets(-1, -1, 0);
3819
3820   button_status = MB_RELEASED;
3821
3822 #if 1
3823   ClearEventQueue();
3824 #endif
3825
3826   while (still_wait)
3827   {
3828     if (PendingEvent())
3829     {
3830       Event event;
3831
3832       NextEvent(&event);
3833
3834       switch (event.type)
3835       {
3836         case EVENT_BUTTONPRESS:
3837         case EVENT_KEYPRESS:
3838           still_wait = FALSE;
3839           break;
3840
3841         case EVENT_KEYRELEASE:
3842           ClearPlayerAction();
3843           break;
3844
3845         default:
3846           HandleOtherEvents(&event);
3847           break;
3848       }
3849     }
3850     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3851     {
3852       still_wait = FALSE;
3853     }
3854
3855     DoAnimation();
3856
3857     /* don't eat all CPU time */
3858     Delay(10);
3859   }
3860 }
3861
3862 #define MAX_REQUEST_LINES               13
3863 #define MAX_REQUEST_LINE_FONT1_LEN      7
3864 #define MAX_REQUEST_LINE_FONT2_LEN      10
3865
3866 boolean Request(char *text, unsigned int req_state)
3867 {
3868   int mx, my, ty, result = -1;
3869   unsigned int old_door_state;
3870   int last_game_status = game_status;   /* save current game status */
3871   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3872   int font_nr = FONT_TEXT_2;
3873 #if 0
3874   int max_word_len = 0;
3875 #endif
3876   char *text_ptr;
3877   int i;
3878
3879 #if 1
3880   global.use_envelope_request = 0;
3881 #endif
3882
3883 #if 1
3884   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3885   {
3886     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3887     font_nr = FONT_TEXT_1;
3888   }
3889 #else
3890   for (text_ptr = text; *text_ptr; text_ptr++)
3891   {
3892     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3893
3894     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
3895     {
3896       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3897 #if 1
3898       font_nr = FONT_TEXT_1;
3899 #else
3900       font_nr = FONT_LEVEL_NUMBER;
3901 #endif
3902
3903       break;
3904     }
3905   }
3906 #endif
3907
3908   if (game_status == GAME_MODE_PLAYING)
3909   {
3910     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3911       BlitScreenToBitmap_EM(backbuffer);
3912     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3913       BlitScreenToBitmap_SP(backbuffer);
3914   }
3915
3916   /* disable deactivated drawing when quick-loading level tape recording */
3917   if (tape.playing && tape.deactivate_display)
3918     TapeDeactivateDisplayOff(TRUE);
3919
3920   SetMouseCursor(CURSOR_DEFAULT);
3921
3922 #if defined(NETWORK_AVALIABLE)
3923   /* pause network game while waiting for request to answer */
3924   if (options.network &&
3925       game_status == GAME_MODE_PLAYING &&
3926       req_state & REQUEST_WAIT_FOR_INPUT)
3927     SendToServer_PausePlaying();
3928 #endif
3929
3930   old_door_state = GetDoorState();
3931
3932   /* simulate releasing mouse button over last gadget, if still pressed */
3933   if (button_status)
3934     HandleGadgets(-1, -1, 0);
3935
3936   UnmapAllGadgets();
3937
3938   /* draw released gadget before proceeding */
3939   // BackToFront();
3940
3941 #if 0
3942   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
3943 #else
3944   if (old_door_state & DOOR_OPEN_1)
3945 #endif
3946   {
3947 #if 1
3948     if (!global.use_envelope_request)
3949       CloseDoor(DOOR_CLOSE_1);
3950 #else
3951     CloseDoor(DOOR_CLOSE_1);
3952 #endif
3953
3954     /* save old door content */
3955     BlitBitmap(bitmap_db_door, bitmap_db_door,
3956                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3957                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
3958   }
3959
3960 #if 1
3961   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3962 #endif
3963
3964   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3965
3966   /* clear door drawing field */
3967   DrawBackground(DX, DY, DXSIZE, DYSIZE);
3968
3969   /* force DOOR font inside door area */
3970   game_status = GAME_MODE_PSEUDO_DOOR;
3971
3972   /* write text for request */
3973   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3974   {
3975     char text_line[max_request_line_len + 1];
3976     int tx, tl, tc = 0;
3977
3978     if (!*text_ptr)
3979       break;
3980
3981     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3982     {
3983       tc = *(text_ptr + tx);
3984       if (!tc || tc == ' ')
3985         break;
3986     }
3987
3988     if (!tl)
3989     { 
3990       text_ptr++; 
3991       ty--; 
3992       continue; 
3993     }
3994
3995     strncpy(text_line, text_ptr, tl);
3996     text_line[tl] = 0;
3997
3998     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3999              DY + 8 + ty * (getFontHeight(font_nr) + 2),
4000              text_line, font_nr);
4001
4002     text_ptr += tl + (tc == ' ' ? 1 : 0);
4003   }
4004
4005   game_status = last_game_status;       /* restore current game status */
4006
4007 #if 1
4008   if (global.use_envelope_request)
4009   {
4010     /* !!! TMP !!! */
4011     FreeToolButtons();
4012     CreateToolButtons();
4013   }
4014 #endif
4015
4016   if (req_state & REQ_ASK)
4017   {
4018     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4019     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4020   }
4021   else if (req_state & REQ_CONFIRM)
4022   {
4023     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4024   }
4025   else if (req_state & REQ_PLAYER)
4026   {
4027     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4028     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4029     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4030     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4031   }
4032
4033   /* copy request gadgets to door backbuffer */
4034   BlitBitmap(drawto, bitmap_db_door,
4035              DX, DY, DXSIZE, DYSIZE,
4036              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4037
4038 #if 1
4039   if (global.use_envelope_request)
4040   {
4041     ShowEnvelopeDoor(text, ACTION_OPENING);
4042
4043     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4044     {
4045       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4046                                    i == TOOL_CTRL_ID_NO)) ||
4047           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4048           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4049                                       i == TOOL_CTRL_ID_PLAYER_2 &&
4050                                       i == TOOL_CTRL_ID_PLAYER_3 &&
4051                                       i == TOOL_CTRL_ID_PLAYER_4)))
4052       {
4053         int x = tool_gadget[i]->x + dDX;
4054         int y = tool_gadget[i]->y + dDY;
4055
4056         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4057       }
4058     }
4059   }
4060 #endif
4061
4062 #if 1
4063   if (!global.use_envelope_request)
4064     OpenDoor(DOOR_OPEN_1);
4065 #else
4066   OpenDoor(DOOR_OPEN_1);
4067 #endif
4068
4069   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4070   {
4071     if (game_status == GAME_MODE_PLAYING)
4072     {
4073       SetPanelBackground();
4074       SetDrawBackgroundMask(REDRAW_DOOR_1);
4075     }
4076     else
4077     {
4078       SetDrawBackgroundMask(REDRAW_FIELD);
4079     }
4080
4081     return FALSE;
4082   }
4083
4084 #if 1
4085   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4086     InitAnimation();
4087 #else
4088   if (game_status != GAME_MODE_MAIN)
4089     InitAnimation();
4090 #endif
4091
4092   button_status = MB_RELEASED;
4093
4094   request_gadget_id = -1;
4095
4096   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4097
4098   while (result < 0)
4099   {
4100     if (PendingEvent())
4101     {
4102       Event event;
4103
4104       NextEvent(&event);
4105
4106       switch (event.type)
4107       {
4108         case EVENT_BUTTONPRESS:
4109         case EVENT_BUTTONRELEASE:
4110         case EVENT_MOTIONNOTIFY:
4111         {
4112           if (event.type == EVENT_MOTIONNOTIFY)
4113           {
4114             if (!PointerInWindow(window))
4115               continue; /* window and pointer are on different screens */
4116
4117             if (!button_status)
4118               continue;
4119
4120             motion_status = TRUE;
4121             mx = ((MotionEvent *) &event)->x;
4122             my = ((MotionEvent *) &event)->y;
4123           }
4124           else
4125           {
4126             motion_status = FALSE;
4127             mx = ((ButtonEvent *) &event)->x;
4128             my = ((ButtonEvent *) &event)->y;
4129             if (event.type == EVENT_BUTTONPRESS)
4130               button_status = ((ButtonEvent *) &event)->button;
4131             else
4132               button_status = MB_RELEASED;
4133           }
4134
4135           /* this sets 'request_gadget_id' */
4136           HandleGadgets(mx, my, button_status);
4137
4138           switch (request_gadget_id)
4139           {
4140             case TOOL_CTRL_ID_YES:
4141               result = TRUE;
4142               break;
4143             case TOOL_CTRL_ID_NO:
4144               result = FALSE;
4145               break;
4146             case TOOL_CTRL_ID_CONFIRM:
4147               result = TRUE | FALSE;
4148               break;
4149
4150             case TOOL_CTRL_ID_PLAYER_1:
4151               result = 1;
4152               break;
4153             case TOOL_CTRL_ID_PLAYER_2:
4154               result = 2;
4155               break;
4156             case TOOL_CTRL_ID_PLAYER_3:
4157               result = 3;
4158               break;
4159             case TOOL_CTRL_ID_PLAYER_4:
4160               result = 4;
4161               break;
4162
4163             default:
4164               break;
4165           }
4166
4167           break;
4168         }
4169
4170         case EVENT_KEYPRESS:
4171           switch (GetEventKey((KeyEvent *)&event, TRUE))
4172           {
4173             case KSYM_space:
4174               if (req_state & REQ_CONFIRM)
4175                 result = 1;
4176               break;
4177
4178             case KSYM_Return:
4179               result = 1;
4180               break;
4181
4182             case KSYM_Escape:
4183 #if defined(TARGET_SDL2)
4184             case KSYM_Back:
4185 #endif
4186               result = 0;
4187               break;
4188
4189             default:
4190               break;
4191           }
4192
4193           if (req_state & REQ_PLAYER)
4194             result = 0;
4195           break;
4196
4197         case EVENT_KEYRELEASE:
4198           ClearPlayerAction();
4199           break;
4200
4201         default:
4202           HandleOtherEvents(&event);
4203           break;
4204       }
4205     }
4206     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4207     {
4208       int joy = AnyJoystick();
4209
4210       if (joy & JOY_BUTTON_1)
4211         result = 1;
4212       else if (joy & JOY_BUTTON_2)
4213         result = 0;
4214     }
4215
4216 #if 1
4217
4218     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4219     {
4220       HandleGameActions();
4221     }
4222     else
4223     {
4224       DoAnimation();
4225
4226       if (!PendingEvent())      /* delay only if no pending events */
4227         Delay(10);
4228     }
4229
4230 #if 1
4231     game_status = GAME_MODE_PSEUDO_DOOR;
4232 #endif
4233
4234     BackToFront();
4235
4236 #if 1
4237     game_status = last_game_status;     /* restore current game status */
4238 #endif
4239
4240 #else
4241
4242     DoAnimation();
4243
4244 #if 1
4245     if (!PendingEvent())        /* delay only if no pending events */
4246       Delay(10);
4247 #else
4248     /* don't eat all CPU time */
4249     Delay(10);
4250 #endif
4251
4252 #endif
4253   }
4254
4255   if (game_status != GAME_MODE_MAIN)
4256     StopAnimation();
4257
4258   UnmapToolButtons();
4259
4260 #if 1
4261   if (global.use_envelope_request)
4262     ShowEnvelopeDoor(text, ACTION_CLOSING);
4263 #endif
4264
4265 #if 1
4266   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
4267 #else
4268   if (!(req_state & REQ_STAY_OPEN))
4269 #endif
4270   {
4271     CloseDoor(DOOR_CLOSE_1);
4272
4273     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4274         (req_state & REQ_REOPEN))
4275       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4276   }
4277
4278   RemapAllGadgets();
4279
4280   if (game_status == GAME_MODE_PLAYING)
4281   {
4282     SetPanelBackground();
4283     SetDrawBackgroundMask(REDRAW_DOOR_1);
4284   }
4285   else
4286   {
4287     SetDrawBackgroundMask(REDRAW_FIELD);
4288   }
4289
4290 #if defined(NETWORK_AVALIABLE)
4291   /* continue network game after request */
4292   if (options.network &&
4293       game_status == GAME_MODE_PLAYING &&
4294       req_state & REQUEST_WAIT_FOR_INPUT)
4295     SendToServer_ContinuePlaying();
4296 #endif
4297
4298   /* restore deactivated drawing when quick-loading level tape recording */
4299   if (tape.playing && tape.deactivate_display)
4300     TapeDeactivateDisplayOn();
4301
4302   return result;
4303 }
4304
4305 unsigned int OpenDoor(unsigned int door_state)
4306 {
4307   if (door_state & DOOR_COPY_BACK)
4308   {
4309     if (door_state & DOOR_OPEN_1)
4310       BlitBitmap(bitmap_db_door, bitmap_db_door,
4311                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4312                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4313
4314     if (door_state & DOOR_OPEN_2)
4315       BlitBitmap(bitmap_db_door, bitmap_db_door,
4316                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
4317                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4318
4319     door_state &= ~DOOR_COPY_BACK;
4320   }
4321
4322   return MoveDoor(door_state);
4323 }
4324
4325 unsigned int CloseDoor(unsigned int door_state)
4326 {
4327   unsigned int old_door_state = GetDoorState();
4328
4329   if (!(door_state & DOOR_NO_COPY_BACK))
4330   {
4331     if (old_door_state & DOOR_OPEN_1)
4332       BlitBitmap(backbuffer, bitmap_db_door,
4333                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4334
4335     if (old_door_state & DOOR_OPEN_2)
4336       BlitBitmap(backbuffer, bitmap_db_door,
4337                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
4338
4339     door_state &= ~DOOR_NO_COPY_BACK;
4340   }
4341
4342   return MoveDoor(door_state);
4343 }
4344
4345 unsigned int GetDoorState()
4346 {
4347   return MoveDoor(DOOR_GET_STATE);
4348 }
4349
4350 unsigned int SetDoorState(unsigned int door_state)
4351 {
4352   return MoveDoor(door_state | DOOR_SET_STATE);
4353 }
4354
4355 unsigned int MoveDoor(unsigned int door_state)
4356 {
4357   static int door1 = DOOR_OPEN_1;
4358   static int door2 = DOOR_CLOSE_2;
4359   unsigned int door_delay = 0;
4360   unsigned int door_delay_value;
4361   int stepsize = 1;
4362
4363   if (door_1.width < 0 || door_1.width > DXSIZE)
4364     door_1.width = DXSIZE;
4365   if (door_1.height < 0 || door_1.height > DYSIZE)
4366     door_1.height = DYSIZE;
4367   if (door_2.width < 0 || door_2.width > VXSIZE)
4368     door_2.width = VXSIZE;
4369   if (door_2.height < 0 || door_2.height > VYSIZE)
4370     door_2.height = VYSIZE;
4371
4372   if (door_state == DOOR_GET_STATE)
4373     return (door1 | door2);
4374
4375   if (door_state & DOOR_SET_STATE)
4376   {
4377     if (door_state & DOOR_ACTION_1)
4378       door1 = door_state & DOOR_ACTION_1;
4379     if (door_state & DOOR_ACTION_2)
4380       door2 = door_state & DOOR_ACTION_2;
4381
4382     return (door1 | door2);
4383   }
4384
4385   if (!(door_state & DOOR_FORCE_REDRAW))
4386   {
4387     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
4388       door_state &= ~DOOR_OPEN_1;
4389     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4390       door_state &= ~DOOR_CLOSE_1;
4391     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4392       door_state &= ~DOOR_OPEN_2;
4393     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4394       door_state &= ~DOOR_CLOSE_2;
4395   }
4396
4397   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
4398                       door_2.step_delay);
4399
4400   if (setup.quick_doors)
4401   {
4402     stepsize = 20;              /* must be chosen to always draw last frame */
4403     door_delay_value = 0;
4404   }
4405
4406   if (global.autoplay_leveldir)
4407   {
4408     door_state |= DOOR_NO_DELAY;
4409     door_state &= ~DOOR_CLOSE_ALL;
4410   }
4411
4412 #if 1
4413   if (game_status == GAME_MODE_EDITOR)
4414     door_state |= DOOR_NO_DELAY;
4415 #endif
4416
4417   if (door_state & DOOR_ACTION)
4418   {
4419     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
4420     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
4421     boolean door_1_done = (!handle_door_1);
4422     boolean door_2_done = (!handle_door_2);
4423     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
4424     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
4425     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
4426     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
4427     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
4428     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
4429     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
4430     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
4431     int door_skip = max_door_size - door_size;
4432     int end = door_size;
4433     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
4434     int k;
4435
4436     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
4437     {
4438       /* opening door sound has priority over simultaneously closing door */
4439       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4440         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4441       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4442         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4443     }
4444
4445     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
4446     {
4447       int x = k;
4448       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4449       GC gc = bitmap->stored_clip_gc;
4450
4451       if (door_state & DOOR_ACTION_1)
4452       {
4453         int a = MIN(x * door_1.step_offset, end);
4454         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
4455         int i = p + door_skip;
4456
4457         if (door_1.anim_mode & ANIM_STATIC_PANEL)
4458         {
4459           BlitBitmap(bitmap_db_door, drawto,
4460                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
4461                      DXSIZE, DYSIZE, DX, DY);
4462         }
4463         else if (x <= a)
4464         {
4465           BlitBitmap(bitmap_db_door, drawto,
4466                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
4467                      DXSIZE, DYSIZE - p / 2, DX, DY);
4468
4469           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
4470         }
4471
4472         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
4473         {
4474           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4475           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
4476           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
4477           int dst2_x = DX,              dst2_y = DY;
4478           int width = i, height = DYSIZE;
4479
4480           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4481           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4482                            dst1_x, dst1_y);
4483
4484           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4485           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4486                            dst2_x, dst2_y);
4487         }
4488         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
4489         {
4490           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
4491           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
4492           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
4493           int dst2_x = DX,              dst2_y = DY;
4494           int width = DXSIZE, height = i;
4495
4496           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4497           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4498                            dst1_x, dst1_y);
4499
4500           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4501           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4502                            dst2_x, dst2_y);
4503         }
4504         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
4505         {
4506           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
4507
4508           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4509           BlitBitmapMasked(bitmap, drawto,
4510                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
4511                            DX + DXSIZE - i, DY + j);
4512           BlitBitmapMasked(bitmap, drawto,
4513                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
4514                            DX + DXSIZE - i, DY + 140 + j);
4515           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
4516                         DY - (DOOR_GFX_PAGEY1 + j));
4517           BlitBitmapMasked(bitmap, drawto,
4518                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
4519                            DX, DY);
4520           BlitBitmapMasked(bitmap, drawto,
4521                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
4522                            DX, DY + 140 - j);
4523
4524           BlitBitmapMasked(bitmap, drawto,
4525                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
4526                            DX, DY + 77 - j);
4527           BlitBitmapMasked(bitmap, drawto,
4528                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
4529                            DX, DY + 203 - j);
4530           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
4531           BlitBitmapMasked(bitmap, drawto,
4532                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
4533                            DX + DXSIZE - i, DY + 77 + j);
4534           BlitBitmapMasked(bitmap, drawto,
4535                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
4536                            DX + DXSIZE - i, DY + 203 + j);
4537         }
4538
4539         redraw_mask |= REDRAW_DOOR_1;
4540         door_1_done = (a == end);
4541       }
4542
4543       if (door_state & DOOR_ACTION_2)
4544       {
4545         int a = MIN(x * door_2.step_offset, door_size);
4546         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
4547         int i = p + door_skip;
4548
4549         if (door_2.anim_mode & ANIM_STATIC_PANEL)
4550         {
4551           BlitBitmap(bitmap_db_door, drawto,
4552                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
4553                      VXSIZE, VYSIZE, VX, VY);
4554         }
4555         else if (x <= VYSIZE)
4556         {
4557           BlitBitmap(bitmap_db_door, drawto,
4558                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
4559                      VXSIZE, VYSIZE - p / 2, VX, VY);
4560
4561           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
4562         }
4563
4564         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
4565         {
4566           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4567           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
4568           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
4569           int dst2_x = VX,              dst2_y = VY;
4570           int width = i, height = VYSIZE;
4571
4572           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4573           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4574                            dst1_x, dst1_y);
4575
4576           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4577           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4578                            dst2_x, dst2_y);
4579         }
4580         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
4581         {
4582           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
4583           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
4584           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
4585           int dst2_x = VX,              dst2_y = VY;
4586           int width = VXSIZE, height = i;
4587
4588           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
4589           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
4590                            dst1_x, dst1_y);
4591
4592           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
4593           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
4594                            dst2_x, dst2_y);
4595         }
4596         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
4597         {
4598           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
4599
4600           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4601           BlitBitmapMasked(bitmap, drawto,
4602                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
4603                            VX + VXSIZE - i, VY + j);
4604           SetClipOrigin(bitmap, gc,
4605                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
4606           BlitBitmapMasked(bitmap, drawto,
4607                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
4608                            VX, VY);
4609
4610           BlitBitmapMasked(bitmap, drawto,
4611                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4612                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
4613           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
4614           BlitBitmapMasked(bitmap, drawto,
4615                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
4616                            i, VYSIZE / 2 - j,
4617                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
4618         }
4619
4620         redraw_mask |= REDRAW_DOOR_2;
4621         door_2_done = (a == VXSIZE);
4622       }
4623
4624       if (!(door_state & DOOR_NO_DELAY))
4625       {
4626         BackToFront();
4627
4628         if (game_status == GAME_MODE_MAIN)
4629           DoAnimation();
4630
4631         WaitUntilDelayReached(&door_delay, door_delay_value);
4632       }
4633     }
4634   }
4635
4636   if (door_state & DOOR_ACTION_1)
4637     door1 = door_state & DOOR_ACTION_1;
4638   if (door_state & DOOR_ACTION_2)
4639     door2 = door_state & DOOR_ACTION_2;
4640
4641   return (door1 | door2);
4642 }
4643
4644 void DrawSpecialEditorDoor()
4645 {
4646   /* draw bigger toolbox window */
4647   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
4648              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
4649              EX - 4, EY - 12);
4650   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4651              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
4652              EX - 6, EY - 4);
4653
4654   redraw_mask |= REDRAW_ALL;
4655 }
4656
4657 void UndrawSpecialEditorDoor()
4658 {
4659   /* draw normal tape recorder window */
4660   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4661              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
4662              EX - 6, EY - 12);
4663
4664   redraw_mask |= REDRAW_ALL;
4665 }
4666
4667
4668 /* ---------- new tool button stuff ---------------------------------------- */
4669
4670 #if 1
4671
4672 static struct
4673 {
4674   int graphic;
4675   struct TextPosInfo *pos;
4676   int gadget_id;
4677   char *infotext;
4678 } toolbutton_info[NUM_TOOL_BUTTONS] =
4679 {
4680   {
4681     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
4682     TOOL_CTRL_ID_YES,                   "yes"
4683   },
4684   {
4685     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
4686     TOOL_CTRL_ID_NO,                    "no"
4687   },
4688   {
4689     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
4690     TOOL_CTRL_ID_CONFIRM,               "confirm"
4691   },
4692   {
4693     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
4694     TOOL_CTRL_ID_PLAYER_1,              "player 1"
4695   },
4696   {
4697     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
4698     TOOL_CTRL_ID_PLAYER_2,              "player 2"
4699   },
4700   {
4701     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
4702     TOOL_CTRL_ID_PLAYER_3,              "player 3"
4703   },
4704   {
4705     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
4706     TOOL_CTRL_ID_PLAYER_4,              "player 4"
4707   }
4708 };
4709
4710 void CreateToolButtons()
4711 {
4712   int i;
4713
4714   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4715   {
4716     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4717     struct TextPosInfo *pos = toolbutton_info[i].pos;
4718     struct GadgetInfo *gi;
4719     Bitmap *deco_bitmap = None;
4720     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4721     unsigned int event_mask = GD_EVENT_RELEASED;
4722     int gd_x   = gfx->src_x;
4723     int gd_y   = gfx->src_y;
4724     int gd_xp  = gfx->src_x + gfx->pressed_xoffset;
4725     int gd_yp  = gfx->src_y + gfx->pressed_yoffset;
4726     int id = i;
4727
4728     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4729     {
4730       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4731
4732       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4733                             pos->size, &deco_bitmap, &deco_x, &deco_y);
4734       deco_xpos = (gfx->width  - pos->size) / 2;
4735       deco_ypos = (gfx->height - pos->size) / 2;
4736     }
4737
4738     gi = CreateGadget(GDI_CUSTOM_ID, id,
4739                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4740                       GDI_X, DX + pos->x,
4741                       GDI_Y, DY + pos->y,
4742                       GDI_WIDTH, gfx->width,
4743                       GDI_HEIGHT, gfx->height,
4744                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4745                       GDI_STATE, GD_BUTTON_UNPRESSED,
4746                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4747                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4748                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4749                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4750                       GDI_DECORATION_SIZE, pos->size, pos->size,
4751                       GDI_DECORATION_SHIFTING, 1, 1,
4752                       GDI_DIRECT_DRAW, FALSE,
4753                       GDI_EVENT_MASK, event_mask,
4754                       GDI_CALLBACK_ACTION, HandleToolButtons,
4755                       GDI_END);
4756
4757     if (gi == NULL)
4758       Error(ERR_EXIT, "cannot create gadget");
4759
4760     tool_gadget[id] = gi;
4761   }
4762 }
4763
4764 #else
4765
4766 /* graphic position values for tool buttons */
4767 #define TOOL_BUTTON_YES_XPOS            2
4768 #define TOOL_BUTTON_YES_YPOS            250
4769 #define TOOL_BUTTON_YES_GFX_YPOS        0
4770 #define TOOL_BUTTON_YES_XSIZE           46
4771 #define TOOL_BUTTON_YES_YSIZE           28
4772 #define TOOL_BUTTON_NO_XPOS             52
4773 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
4774 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
4775 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
4776 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
4777 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
4778 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
4779 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
4780 #define TOOL_BUTTON_CONFIRM_XSIZE       96
4781 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
4782 #define TOOL_BUTTON_PLAYER_XSIZE        30
4783 #define TOOL_BUTTON_PLAYER_YSIZE        30
4784 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
4785 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
4786 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
4787 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
4788 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4789                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4790 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4791                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4792 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4793                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
4794 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
4795                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
4796 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4797                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4798 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4799                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
4800 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4801                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4802 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
4803                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
4804
4805 static struct
4806 {
4807   int xpos, ypos;
4808   int x, y;
4809   int width, height;
4810   int gadget_id;
4811   char *infotext;
4812 } toolbutton_info[NUM_TOOL_BUTTONS] =
4813 {
4814   {
4815     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
4816     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
4817     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
4818     TOOL_CTRL_ID_YES,
4819     "yes"
4820   },
4821   {
4822     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
4823     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
4824     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
4825     TOOL_CTRL_ID_NO,
4826     "no"
4827   },
4828   {
4829     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
4830     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
4831     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
4832     TOOL_CTRL_ID_CONFIRM,
4833     "confirm"
4834   },
4835   {
4836     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4837     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
4838     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4839     TOOL_CTRL_ID_PLAYER_1,
4840     "player 1"
4841   },
4842   {
4843     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4844     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
4845     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4846     TOOL_CTRL_ID_PLAYER_2,
4847     "player 2"
4848   },
4849   {
4850     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4851     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
4852     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4853     TOOL_CTRL_ID_PLAYER_3,
4854     "player 3"
4855   },
4856   {
4857     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
4858     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
4859     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
4860     TOOL_CTRL_ID_PLAYER_4,
4861     "player 4"
4862   }
4863 };
4864
4865 void CreateToolButtons()
4866 {
4867   int i;
4868
4869   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4870   {
4871     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
4872     Bitmap *deco_bitmap = None;
4873     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4874     struct GadgetInfo *gi;
4875     unsigned int event_mask;
4876     int gd_xoffset, gd_yoffset;
4877     int gd_x1, gd_x2, gd_y;
4878     int id = i;
4879
4880     event_mask = GD_EVENT_RELEASED;
4881
4882     gd_xoffset = toolbutton_info[i].xpos;
4883     gd_yoffset = toolbutton_info[i].ypos;
4884     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4885     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4886     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
4887
4888     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4889     {
4890       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4891
4892       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
4893                            &deco_bitmap, &deco_x, &deco_y);
4894       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
4895       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
4896     }
4897
4898     gi = CreateGadget(GDI_CUSTOM_ID, id,
4899                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4900                       GDI_X, DX + toolbutton_info[i].x,
4901                       GDI_Y, DY + toolbutton_info[i].y,
4902                       GDI_WIDTH, toolbutton_info[i].width,
4903                       GDI_HEIGHT, toolbutton_info[i].height,
4904                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4905                       GDI_STATE, GD_BUTTON_UNPRESSED,
4906                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
4907                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
4908                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4909                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4910                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
4911                       GDI_DECORATION_SHIFTING, 1, 1,
4912                       GDI_DIRECT_DRAW, FALSE,
4913                       GDI_EVENT_MASK, event_mask,
4914                       GDI_CALLBACK_ACTION, HandleToolButtons,
4915                       GDI_END);
4916
4917     if (gi == NULL)
4918       Error(ERR_EXIT, "cannot create gadget");
4919
4920     tool_gadget[id] = gi;
4921   }
4922 }
4923
4924 #endif
4925
4926 void FreeToolButtons()
4927 {
4928   int i;
4929
4930   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4931     FreeGadget(tool_gadget[i]);
4932 }
4933
4934 static void UnmapToolButtons()
4935 {
4936   int i;
4937
4938   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4939     UnmapGadget(tool_gadget[i]);
4940 }
4941
4942 static void HandleToolButtons(struct GadgetInfo *gi)
4943 {
4944   request_gadget_id = gi->custom_id;
4945 }
4946
4947 static struct Mapping_EM_to_RND_object
4948 {
4949   int element_em;
4950   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
4951   boolean is_backside;                  /* backside of moving element */
4952
4953   int element_rnd;
4954   int action;
4955   int direction;
4956 }
4957 em_object_mapping_list[] =
4958 {
4959   {
4960     Xblank,                             TRUE,   FALSE,
4961     EL_EMPTY,                           -1, -1
4962   },
4963   {
4964     Yacid_splash_eB,                    FALSE,  FALSE,
4965     EL_ACID_SPLASH_RIGHT,               -1, -1
4966   },
4967   {
4968     Yacid_splash_wB,                    FALSE,  FALSE,
4969     EL_ACID_SPLASH_LEFT,                -1, -1
4970   },
4971
4972 #ifdef EM_ENGINE_BAD_ROLL
4973   {
4974     Xstone_force_e,                     FALSE,  FALSE,
4975     EL_ROCK,                            -1, MV_BIT_RIGHT
4976   },
4977   {
4978     Xstone_force_w,                     FALSE,  FALSE,
4979     EL_ROCK,                            -1, MV_BIT_LEFT
4980   },
4981   {
4982     Xnut_force_e,                       FALSE,  FALSE,
4983     EL_NUT,                             -1, MV_BIT_RIGHT
4984   },
4985   {
4986     Xnut_force_w,                       FALSE,  FALSE,
4987     EL_NUT,                             -1, MV_BIT_LEFT
4988   },
4989   {
4990     Xspring_force_e,                    FALSE,  FALSE,
4991     EL_SPRING,                          -1, MV_BIT_RIGHT
4992   },
4993   {
4994     Xspring_force_w,                    FALSE,  FALSE,
4995     EL_SPRING,                          -1, MV_BIT_LEFT
4996   },
4997   {
4998     Xemerald_force_e,                   FALSE,  FALSE,
4999     EL_EMERALD,                         -1, MV_BIT_RIGHT
5000   },
5001   {
5002     Xemerald_force_w,                   FALSE,  FALSE,
5003     EL_EMERALD,                         -1, MV_BIT_LEFT
5004   },
5005   {
5006     Xdiamond_force_e,                   FALSE,  FALSE,
5007     EL_DIAMOND,                         -1, MV_BIT_RIGHT
5008   },
5009   {
5010     Xdiamond_force_w,                   FALSE,  FALSE,
5011     EL_DIAMOND,                         -1, MV_BIT_LEFT
5012   },
5013   {
5014     Xbomb_force_e,                      FALSE,  FALSE,
5015     EL_BOMB,                            -1, MV_BIT_RIGHT
5016   },
5017   {
5018     Xbomb_force_w,                      FALSE,  FALSE,
5019     EL_BOMB,                            -1, MV_BIT_LEFT
5020   },
5021 #endif  /* EM_ENGINE_BAD_ROLL */
5022
5023   {
5024     Xstone,                             TRUE,   FALSE,
5025     EL_ROCK,                            -1, -1
5026   },
5027   {
5028     Xstone_pause,                       FALSE,  FALSE,
5029     EL_ROCK,                            -1, -1
5030   },
5031   {
5032     Xstone_fall,                        FALSE,  FALSE,
5033     EL_ROCK,                            -1, -1
5034   },
5035   {
5036     Ystone_s,                           FALSE,  FALSE,
5037     EL_ROCK,                            ACTION_FALLING, -1
5038   },
5039   {
5040     Ystone_sB,                          FALSE,  TRUE,
5041     EL_ROCK,                            ACTION_FALLING, -1
5042   },
5043   {
5044     Ystone_e,                           FALSE,  FALSE,
5045     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
5046   },
5047   {
5048     Ystone_eB,                          FALSE,  TRUE,
5049     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
5050   },
5051   {
5052     Ystone_w,                           FALSE,  FALSE,
5053     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
5054   },
5055   {
5056     Ystone_wB,                          FALSE,  TRUE,
5057     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
5058   },
5059   {
5060     Xnut,                               TRUE,   FALSE,
5061     EL_NUT,                             -1, -1
5062   },
5063   {
5064     Xnut_pause,                         FALSE,  FALSE,
5065     EL_NUT,                             -1, -1
5066   },
5067   {
5068     Xnut_fall,                          FALSE,  FALSE,
5069     EL_NUT,                             -1, -1
5070   },
5071   {
5072     Ynut_s,                             FALSE,  FALSE,
5073     EL_NUT,                             ACTION_FALLING, -1
5074   },
5075   {
5076     Ynut_sB,                            FALSE,  TRUE,
5077     EL_NUT,                             ACTION_FALLING, -1
5078   },
5079   {
5080     Ynut_e,                             FALSE,  FALSE,
5081     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
5082   },
5083   {
5084     Ynut_eB,                            FALSE,  TRUE,
5085     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
5086   },
5087   {
5088     Ynut_w,                             FALSE,  FALSE,
5089     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
5090   },
5091   {
5092     Ynut_wB,                            FALSE,  TRUE,
5093     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
5094   },
5095   {
5096     Xbug_n,                             TRUE,   FALSE,
5097     EL_BUG_UP,                          -1, -1
5098   },
5099   {
5100     Xbug_e,                             TRUE,   FALSE,
5101     EL_BUG_RIGHT,                       -1, -1
5102   },
5103   {
5104     Xbug_s,                             TRUE,   FALSE,
5105     EL_BUG_DOWN,                        -1, -1
5106   },
5107   {
5108     Xbug_w,                             TRUE,   FALSE,
5109     EL_BUG_LEFT,                        -1, -1
5110   },
5111   {
5112     Xbug_gon,                           FALSE,  FALSE,
5113     EL_BUG_UP,                          -1, -1
5114   },
5115   {
5116     Xbug_goe,                           FALSE,  FALSE,
5117     EL_BUG_RIGHT,                       -1, -1
5118   },
5119   {
5120     Xbug_gos,                           FALSE,  FALSE,
5121     EL_BUG_DOWN,                        -1, -1
5122   },
5123   {
5124     Xbug_gow,                           FALSE,  FALSE,
5125     EL_BUG_LEFT,                        -1, -1
5126   },
5127   {
5128     Ybug_n,                             FALSE,  FALSE,
5129     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
5130   },
5131   {
5132     Ybug_nB,                            FALSE,  TRUE,
5133     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
5134   },
5135   {
5136     Ybug_e,                             FALSE,  FALSE,
5137     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
5138   },
5139   {
5140     Ybug_eB,                            FALSE,  TRUE,
5141     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
5142   },
5143   {
5144     Ybug_s,                             FALSE,  FALSE,
5145     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
5146   },
5147   {
5148     Ybug_sB,                            FALSE,  TRUE,
5149     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
5150   },
5151   {
5152     Ybug_w,                             FALSE,  FALSE,
5153     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
5154   },
5155   {
5156     Ybug_wB,                            FALSE,  TRUE,
5157     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
5158   },
5159   {
5160     Ybug_w_n,                           FALSE,  FALSE,
5161     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5162   },
5163   {
5164     Ybug_n_e,                           FALSE,  FALSE,
5165     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5166   },
5167   {
5168     Ybug_e_s,                           FALSE,  FALSE,
5169     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5170   },
5171   {
5172     Ybug_s_w,                           FALSE,  FALSE,
5173     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5174   },
5175   {
5176     Ybug_e_n,                           FALSE,  FALSE,
5177     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5178   },
5179   {
5180     Ybug_s_e,                           FALSE,  FALSE,
5181     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5182   },
5183   {
5184     Ybug_w_s,                           FALSE,  FALSE,
5185     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5186   },
5187   {
5188     Ybug_n_w,                           FALSE,  FALSE,
5189     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5190   },
5191   {
5192     Ybug_stone,                         FALSE,  FALSE,
5193     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
5194   },
5195   {
5196     Ybug_spring,                        FALSE,  FALSE,
5197     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
5198   },
5199   {
5200     Xtank_n,                            TRUE,   FALSE,
5201     EL_SPACESHIP_UP,                    -1, -1
5202   },
5203   {
5204     Xtank_e,                            TRUE,   FALSE,
5205     EL_SPACESHIP_RIGHT,                 -1, -1
5206   },
5207   {
5208     Xtank_s,                            TRUE,   FALSE,
5209     EL_SPACESHIP_DOWN,                  -1, -1
5210   },
5211   {
5212     Xtank_w,                            TRUE,   FALSE,
5213     EL_SPACESHIP_LEFT,                  -1, -1
5214   },
5215   {
5216     Xtank_gon,                          FALSE,  FALSE,
5217     EL_SPACESHIP_UP,                    -1, -1
5218   },
5219   {
5220     Xtank_goe,                          FALSE,  FALSE,
5221     EL_SPACESHIP_RIGHT,                 -1, -1
5222   },
5223   {
5224     Xtank_gos,                          FALSE,  FALSE,
5225     EL_SPACESHIP_DOWN,                  -1, -1
5226   },
5227   {
5228     Xtank_gow,                          FALSE,  FALSE,
5229     EL_SPACESHIP_LEFT,                  -1, -1
5230   },
5231   {
5232     Ytank_n,                            FALSE,  FALSE,
5233     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
5234   },
5235   {
5236     Ytank_nB,                           FALSE,  TRUE,
5237     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
5238   },
5239   {
5240     Ytank_e,                            FALSE,  FALSE,
5241     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
5242   },
5243   {
5244     Ytank_eB,                           FALSE,  TRUE,
5245     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
5246   },
5247   {
5248     Ytank_s,                            FALSE,  FALSE,
5249     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
5250   },
5251   {
5252     Ytank_sB,                           FALSE,  TRUE,
5253     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
5254   },
5255   {
5256     Ytank_w,                            FALSE,  FALSE,
5257     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
5258   },
5259   {
5260     Ytank_wB,                           FALSE,  TRUE,
5261     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
5262   },
5263   {
5264     Ytank_w_n,                          FALSE,  FALSE,
5265     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5266   },
5267   {
5268     Ytank_n_e,                          FALSE,  FALSE,
5269     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5270   },
5271   {
5272     Ytank_e_s,                          FALSE,  FALSE,
5273     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5274   },
5275   {
5276     Ytank_s_w,                          FALSE,  FALSE,
5277     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5278   },
5279   {
5280     Ytank_e_n,                          FALSE,  FALSE,
5281     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
5282   },
5283   {
5284     Ytank_s_e,                          FALSE,  FALSE,
5285     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
5286   },
5287   {
5288     Ytank_w_s,                          FALSE,  FALSE,
5289     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
5290   },
5291   {
5292     Ytank_n_w,                          FALSE,  FALSE,
5293     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
5294   },
5295   {
5296     Ytank_stone,                        FALSE,  FALSE,
5297     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
5298   },
5299   {
5300     Ytank_spring,                       FALSE,  FALSE,
5301     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
5302   },
5303   {
5304     Xandroid,                           TRUE,   FALSE,
5305     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
5306   },
5307   {
5308     Xandroid_1_n,                       FALSE,  FALSE,
5309     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
5310   },
5311   {
5312     Xandroid_2_n,                       FALSE,  FALSE,
5313     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
5314   },
5315   {
5316     Xandroid_1_e,                       FALSE,  FALSE,
5317     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5318   },
5319   {
5320     Xandroid_2_e,                       FALSE,  FALSE,
5321     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
5322   },
5323   {
5324     Xandroid_1_w,                       FALSE,  FALSE,
5325     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5326   },
5327   {
5328     Xandroid_2_w,                       FALSE,  FALSE,
5329     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
5330   },
5331   {
5332     Xandroid_1_s,                       FALSE,  FALSE,
5333     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5334   },
5335   {
5336     Xandroid_2_s,                       FALSE,  FALSE,
5337     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
5338   },
5339   {
5340     Yandroid_n,                         FALSE,  FALSE,
5341     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5342   },
5343   {
5344     Yandroid_nB,                        FALSE,  TRUE,
5345     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
5346   },
5347   {
5348     Yandroid_ne,                        FALSE,  FALSE,
5349     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
5350   },
5351   {
5352     Yandroid_neB,                       FALSE,  TRUE,
5353     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
5354   },
5355   {
5356     Yandroid_e,                         FALSE,  FALSE,
5357     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5358   },
5359   {
5360     Yandroid_eB,                        FALSE,  TRUE,
5361     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
5362   },
5363   {
5364     Yandroid_se,                        FALSE,  FALSE,
5365     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
5366   },
5367   {
5368     Yandroid_seB,                       FALSE,  TRUE,
5369     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
5370   },
5371   {
5372     Yandroid_s,                         FALSE,  FALSE,
5373     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5374   },
5375   {
5376     Yandroid_sB,                        FALSE,  TRUE,
5377     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
5378   },
5379   {
5380     Yandroid_sw,                        FALSE,  FALSE,
5381     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
5382   },
5383   {
5384     Yandroid_swB,                       FALSE,  TRUE,
5385     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
5386   },
5387   {
5388     Yandroid_w,                         FALSE,  FALSE,
5389     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5390   },
5391   {
5392     Yandroid_wB,                        FALSE,  TRUE,
5393     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
5394   },
5395   {
5396     Yandroid_nw,                        FALSE,  FALSE,
5397     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
5398   },
5399   {
5400     Yandroid_nwB,                       FALSE,  TRUE,
5401     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
5402   },
5403   {
5404     Xspring,                            TRUE,   FALSE,
5405     EL_SPRING,                          -1, -1
5406   },
5407   {
5408     Xspring_pause,                      FALSE,  FALSE,
5409     EL_SPRING,                          -1, -1
5410   },
5411   {
5412     Xspring_e,                          FALSE,  FALSE,
5413     EL_SPRING,                          -1, -1
5414   },
5415   {
5416     Xspring_w,                          FALSE,  FALSE,
5417     EL_SPRING,                          -1, -1
5418   },
5419   {
5420     Xspring_fall,                       FALSE,  FALSE,
5421     EL_SPRING,                          -1, -1
5422   },
5423   {
5424     Yspring_s,                          FALSE,  FALSE,
5425     EL_SPRING,                          ACTION_FALLING, -1
5426   },
5427   {
5428     Yspring_sB,                         FALSE,  TRUE,
5429     EL_SPRING,                          ACTION_FALLING, -1
5430   },
5431   {
5432     Yspring_e,                          FALSE,  FALSE,
5433     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5434   },
5435   {
5436     Yspring_eB,                         FALSE,  TRUE,
5437     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
5438   },
5439   {
5440     Yspring_w,                          FALSE,  FALSE,
5441     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5442   },
5443   {
5444     Yspring_wB,                         FALSE,  TRUE,
5445     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
5446   },
5447   {
5448     Yspring_kill_e,                     FALSE,  FALSE,
5449     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5450   },
5451   {
5452     Yspring_kill_eB,                    FALSE,  TRUE,
5453     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
5454   },
5455   {
5456     Yspring_kill_w,                     FALSE,  FALSE,
5457     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5458   },
5459   {
5460     Yspring_kill_wB,                    FALSE,  TRUE,
5461     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
5462   },
5463   {
5464     Xeater_n,                           TRUE,   FALSE,
5465     EL_YAMYAM_UP,                       -1, -1
5466   },
5467   {
5468     Xeater_e,                           TRUE,   FALSE,
5469     EL_YAMYAM_RIGHT,                    -1, -1
5470   },
5471   {
5472     Xeater_w,                           TRUE,   FALSE,
5473     EL_YAMYAM_LEFT,                     -1, -1
5474   },
5475   {
5476     Xeater_s,                           TRUE,   FALSE,
5477     EL_YAMYAM_DOWN,                     -1, -1
5478   },
5479   {
5480     Yeater_n,                           FALSE,  FALSE,
5481     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5482   },
5483   {
5484     Yeater_nB,                          FALSE,  TRUE,
5485     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
5486   },
5487   {
5488     Yeater_e,                           FALSE,  FALSE,
5489     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5490   },
5491   {
5492     Yeater_eB,                          FALSE,  TRUE,
5493     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5494   },
5495   {
5496     Yeater_s,                           FALSE,  FALSE,
5497     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5498   },
5499   {
5500     Yeater_sB,                          FALSE,  TRUE,
5501     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5502   },
5503   {
5504     Yeater_w,                           FALSE,  FALSE,
5505     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5506   },
5507   {
5508     Yeater_wB,                          FALSE,  TRUE,
5509     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5510   },
5511   {
5512     Yeater_stone,                       FALSE,  FALSE,
5513     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
5514   },
5515   {
5516     Yeater_spring,                      FALSE,  FALSE,
5517     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
5518   },
5519   {
5520     Xalien,                             TRUE,   FALSE,
5521     EL_ROBOT,                           -1, -1
5522   },
5523   {
5524     Xalien_pause,                       FALSE,  FALSE,
5525     EL_ROBOT,                           -1, -1
5526   },
5527   {
5528     Yalien_n,                           FALSE,  FALSE,
5529     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5530   },
5531   {
5532     Yalien_nB,                          FALSE,  TRUE,
5533     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5534   },
5535   {
5536     Yalien_e,                           FALSE,  FALSE,
5537     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5538   },
5539   {
5540     Yalien_eB,                          FALSE,  TRUE,
5541     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5542   },
5543   {
5544     Yalien_s,                           FALSE,  FALSE,
5545     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5546   },
5547   {
5548     Yalien_sB,                          FALSE,  TRUE,
5549     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5550   },
5551   {
5552     Yalien_w,                           FALSE,  FALSE,
5553     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5554   },
5555   {
5556     Yalien_wB,                          FALSE,  TRUE,
5557     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5558   },
5559   {
5560     Yalien_stone,                       FALSE,  FALSE,
5561     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
5562   },
5563   {
5564     Yalien_spring,                      FALSE,  FALSE,
5565     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
5566   },
5567   {
5568     Xemerald,                           TRUE,   FALSE,
5569     EL_EMERALD,                         -1, -1
5570   },
5571   {
5572     Xemerald_pause,                     FALSE,  FALSE,
5573     EL_EMERALD,                         -1, -1
5574   },
5575   {
5576     Xemerald_fall,                      FALSE,  FALSE,
5577     EL_EMERALD,                         -1, -1
5578   },
5579   {
5580     Xemerald_shine,                     FALSE,  FALSE,
5581     EL_EMERALD,                         ACTION_TWINKLING, -1
5582   },
5583   {
5584     Yemerald_s,                         FALSE,  FALSE,
5585     EL_EMERALD,                         ACTION_FALLING, -1
5586   },
5587   {
5588     Yemerald_sB,                        FALSE,  TRUE,
5589     EL_EMERALD,                         ACTION_FALLING, -1
5590   },
5591   {
5592     Yemerald_e,                         FALSE,  FALSE,
5593     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5594   },
5595   {
5596     Yemerald_eB,                        FALSE,  TRUE,
5597     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5598   },
5599   {
5600     Yemerald_w,                         FALSE,  FALSE,
5601     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5602   },
5603   {
5604     Yemerald_wB,                        FALSE,  TRUE,
5605     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5606   },
5607   {
5608     Yemerald_eat,                       FALSE,  FALSE,
5609     EL_EMERALD,                         ACTION_COLLECTING, -1
5610   },
5611   {
5612     Yemerald_stone,                     FALSE,  FALSE,
5613     EL_NUT,                             ACTION_BREAKING, -1
5614   },
5615   {
5616     Xdiamond,                           TRUE,   FALSE,
5617     EL_DIAMOND,                         -1, -1
5618   },
5619   {
5620     Xdiamond_pause,                     FALSE,  FALSE,
5621     EL_DIAMOND,                         -1, -1
5622   },
5623   {
5624     Xdiamond_fall,                      FALSE,  FALSE,
5625     EL_DIAMOND,                         -1, -1
5626   },
5627   {
5628     Xdiamond_shine,                     FALSE,  FALSE,
5629     EL_DIAMOND,                         ACTION_TWINKLING, -1
5630   },
5631   {
5632     Ydiamond_s,                         FALSE,  FALSE,
5633     EL_DIAMOND,                         ACTION_FALLING, -1
5634   },
5635   {
5636     Ydiamond_sB,                        FALSE,  TRUE,
5637     EL_DIAMOND,                         ACTION_FALLING, -1
5638   },
5639   {
5640     Ydiamond_e,                         FALSE,  FALSE,
5641     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5642   },
5643   {
5644     Ydiamond_eB,                        FALSE,  TRUE,
5645     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5646   },
5647   {
5648     Ydiamond_w,                         FALSE,  FALSE,
5649     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5650   },
5651   {
5652     Ydiamond_wB,                        FALSE,  TRUE,
5653     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5654   },
5655   {
5656     Ydiamond_eat,                       FALSE,  FALSE,
5657     EL_DIAMOND,                         ACTION_COLLECTING, -1
5658   },
5659   {
5660     Ydiamond_stone,                     FALSE,  FALSE,
5661     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
5662   },
5663   {
5664     Xdrip_fall,                         TRUE,   FALSE,
5665     EL_AMOEBA_DROP,                     -1, -1
5666   },
5667   {
5668     Xdrip_stretch,                      FALSE,  FALSE,
5669     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5670   },
5671   {
5672     Xdrip_stretchB,                     FALSE,  TRUE,
5673     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5674   },
5675   {
5676     Xdrip_eat,                          FALSE,  FALSE,
5677     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
5678   },
5679   {
5680     Ydrip_s1,                           FALSE,  FALSE,
5681     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5682   },
5683   {
5684     Ydrip_s1B,                          FALSE,  TRUE,
5685     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5686   },
5687   {
5688     Ydrip_s2,                           FALSE,  FALSE,
5689     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5690   },
5691   {
5692     Ydrip_s2B,                          FALSE,  TRUE,
5693     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5694   },
5695   {
5696     Xbomb,                              TRUE,   FALSE,
5697     EL_BOMB,                            -1, -1
5698   },
5699   {
5700     Xbomb_pause,                        FALSE,  FALSE,
5701     EL_BOMB,                            -1, -1
5702   },
5703   {
5704     Xbomb_fall,                         FALSE,  FALSE,
5705     EL_BOMB,                            -1, -1
5706   },
5707   {
5708     Ybomb_s,                            FALSE,  FALSE,
5709     EL_BOMB,                            ACTION_FALLING, -1
5710   },
5711   {
5712     Ybomb_sB,                           FALSE,  TRUE,
5713     EL_BOMB,                            ACTION_FALLING, -1
5714   },
5715   {
5716     Ybomb_e,                            FALSE,  FALSE,
5717     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5718   },
5719   {
5720     Ybomb_eB,                           FALSE,  TRUE,
5721     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5722   },
5723   {
5724     Ybomb_w,                            FALSE,  FALSE,
5725     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5726   },
5727   {
5728     Ybomb_wB,                           FALSE,  TRUE,
5729     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5730   },
5731   {
5732     Ybomb_eat,                          FALSE,  FALSE,
5733     EL_BOMB,                            ACTION_ACTIVATING, -1
5734   },
5735   {
5736     Xballoon,                           TRUE,   FALSE,
5737     EL_BALLOON,                         -1, -1
5738   },
5739   {
5740     Yballoon_n,                         FALSE,  FALSE,
5741     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5742   },
5743   {
5744     Yballoon_nB,                        FALSE,  TRUE,
5745     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5746   },
5747   {
5748     Yballoon_e,                         FALSE,  FALSE,
5749     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5750   },
5751   {
5752     Yballoon_eB,                        FALSE,  TRUE,
5753     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5754   },
5755   {
5756     Yballoon_s,                         FALSE,  FALSE,
5757     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5758   },
5759   {
5760     Yballoon_sB,                        FALSE,  TRUE,
5761     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5762   },
5763   {
5764     Yballoon_w,                         FALSE,  FALSE,
5765     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5766   },
5767   {
5768     Yballoon_wB,                        FALSE,  TRUE,
5769     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5770   },
5771   {
5772     Xgrass,                             TRUE,   FALSE,
5773     EL_EMC_GRASS,                       -1, -1
5774   },
5775   {
5776     Ygrass_nB,                          FALSE,  FALSE,
5777     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
5778   },
5779   {
5780     Ygrass_eB,                          FALSE,  FALSE,
5781     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
5782   },
5783   {
5784     Ygrass_sB,                          FALSE,  FALSE,
5785     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
5786   },
5787   {
5788     Ygrass_wB,                          FALSE,  FALSE,
5789     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
5790   },
5791   {
5792     Xdirt,                              TRUE,   FALSE,
5793     EL_SAND,                            -1, -1
5794   },
5795   {
5796     Ydirt_nB,                           FALSE,  FALSE,
5797     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
5798   },
5799   {
5800     Ydirt_eB,                           FALSE,  FALSE,
5801     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
5802   },
5803   {
5804     Ydirt_sB,                           FALSE,  FALSE,
5805     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
5806   },
5807   {
5808     Ydirt_wB,                           FALSE,  FALSE,
5809     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
5810   },
5811   {
5812     Xacid_ne,                           TRUE,   FALSE,
5813     EL_ACID_POOL_TOPRIGHT,              -1, -1
5814   },
5815   {
5816     Xacid_se,                           TRUE,   FALSE,
5817     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
5818   },
5819   {
5820     Xacid_s,                            TRUE,   FALSE,
5821     EL_ACID_POOL_BOTTOM,                -1, -1
5822   },
5823   {
5824     Xacid_sw,                           TRUE,   FALSE,
5825     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
5826   },
5827   {
5828     Xacid_nw,                           TRUE,   FALSE,
5829     EL_ACID_POOL_TOPLEFT,               -1, -1
5830   },
5831   {
5832     Xacid_1,                            TRUE,   FALSE,
5833     EL_ACID,                            -1, -1
5834   },
5835   {
5836     Xacid_2,                            FALSE,  FALSE,
5837     EL_ACID,                            -1, -1
5838   },
5839   {
5840     Xacid_3,                            FALSE,  FALSE,
5841     EL_ACID,                            -1, -1
5842   },
5843   {
5844     Xacid_4,                            FALSE,  FALSE,
5845     EL_ACID,                            -1, -1
5846   },
5847   {
5848     Xacid_5,                            FALSE,  FALSE,
5849     EL_ACID,                            -1, -1
5850   },
5851   {
5852     Xacid_6,                            FALSE,  FALSE,
5853     EL_ACID,                            -1, -1
5854   },
5855   {
5856     Xacid_7,                            FALSE,  FALSE,
5857     EL_ACID,                            -1, -1
5858   },
5859   {
5860     Xacid_8,                            FALSE,  FALSE,
5861     EL_ACID,                            -1, -1
5862   },
5863   {
5864     Xball_1,                            TRUE,   FALSE,
5865     EL_EMC_MAGIC_BALL,                  -1, -1
5866   },
5867   {
5868     Xball_1B,                           FALSE,  FALSE,
5869     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5870   },
5871   {
5872     Xball_2,                            FALSE,  FALSE,
5873     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5874   },
5875   {
5876     Xball_2B,                           FALSE,  FALSE,
5877     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5878   },
5879   {
5880     Yball_eat,                          FALSE,  FALSE,
5881     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
5882   },
5883   {
5884     Ykey_1_eat,                         FALSE,  FALSE,
5885     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
5886   },
5887   {
5888     Ykey_2_eat,                         FALSE,  FALSE,
5889     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
5890   },
5891   {
5892     Ykey_3_eat,                         FALSE,  FALSE,
5893     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
5894   },
5895   {
5896     Ykey_4_eat,                         FALSE,  FALSE,
5897     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
5898   },
5899   {
5900     Ykey_5_eat,                         FALSE,  FALSE,
5901     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
5902   },
5903   {
5904     Ykey_6_eat,                         FALSE,  FALSE,
5905     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
5906   },
5907   {
5908     Ykey_7_eat,                         FALSE,  FALSE,
5909     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
5910   },
5911   {
5912     Ykey_8_eat,                         FALSE,  FALSE,
5913     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
5914   },
5915   {
5916     Ylenses_eat,                        FALSE,  FALSE,
5917     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
5918   },
5919   {
5920     Ymagnify_eat,                       FALSE,  FALSE,
5921     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
5922   },
5923   {
5924     Ygrass_eat,                         FALSE,  FALSE,
5925     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
5926   },
5927   {
5928     Ydirt_eat,                          FALSE,  FALSE,
5929     EL_SAND,                            ACTION_SNAPPING, -1
5930   },
5931   {
5932     Xgrow_ns,                           TRUE,   FALSE,
5933     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
5934   },
5935   {
5936     Ygrow_ns_eat,                       FALSE,  FALSE,
5937     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
5938   },
5939   {
5940     Xgrow_ew,                           TRUE,   FALSE,
5941     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
5942   },
5943   {
5944     Ygrow_ew_eat,                       FALSE,  FALSE,
5945     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
5946   },
5947   {
5948     Xwonderwall,                        TRUE,   FALSE,
5949     EL_MAGIC_WALL,                      -1, -1
5950   },
5951   {
5952     XwonderwallB,                       FALSE,  FALSE,
5953     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
5954   },
5955   {
5956     Xamoeba_1,                          TRUE,   FALSE,
5957     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5958   },
5959   {
5960     Xamoeba_2,                          FALSE,  FALSE,
5961     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5962   },
5963   {
5964     Xamoeba_3,                          FALSE,  FALSE,
5965     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5966   },
5967   {
5968     Xamoeba_4,                          FALSE,  FALSE,
5969     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5970   },
5971   {
5972     Xamoeba_5,                          TRUE,   FALSE,
5973     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5974   },
5975   {
5976     Xamoeba_6,                          FALSE,  FALSE,
5977     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5978   },
5979   {
5980     Xamoeba_7,                          FALSE,  FALSE,
5981     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5982   },
5983   {
5984     Xamoeba_8,                          FALSE,  FALSE,
5985     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5986   },
5987   {
5988     Xdoor_1,                            TRUE,   FALSE,
5989     EL_EM_GATE_1,                       -1, -1
5990   },
5991   {
5992     Xdoor_2,                            TRUE,   FALSE,
5993     EL_EM_GATE_2,                       -1, -1
5994   },
5995   {
5996     Xdoor_3,                            TRUE,   FALSE,
5997     EL_EM_GATE_3,                       -1, -1
5998   },
5999   {
6000     Xdoor_4,                            TRUE,   FALSE,
6001     EL_EM_GATE_4,                       -1, -1
6002   },
6003   {
6004     Xdoor_5,                            TRUE,   FALSE,
6005     EL_EMC_GATE_5,                      -1, -1
6006   },
6007   {
6008     Xdoor_6,                            TRUE,   FALSE,
6009     EL_EMC_GATE_6,                      -1, -1
6010   },
6011   {
6012     Xdoor_7,                            TRUE,   FALSE,
6013     EL_EMC_GATE_7,                      -1, -1
6014   },
6015   {
6016     Xdoor_8,                            TRUE,   FALSE,
6017     EL_EMC_GATE_8,                      -1, -1
6018   },
6019   {
6020     Xkey_1,                             TRUE,   FALSE,
6021     EL_EM_KEY_1,                        -1, -1
6022   },
6023   {
6024     Xkey_2,                             TRUE,   FALSE,
6025     EL_EM_KEY_2,                        -1, -1
6026   },
6027   {
6028     Xkey_3,                             TRUE,   FALSE,
6029     EL_EM_KEY_3,                        -1, -1
6030   },
6031   {
6032     Xkey_4,                             TRUE,   FALSE,
6033     EL_EM_KEY_4,                        -1, -1
6034   },
6035   {
6036     Xkey_5,                             TRUE,   FALSE,
6037     EL_EMC_KEY_5,                       -1, -1
6038   },
6039   {
6040     Xkey_6,                             TRUE,   FALSE,
6041     EL_EMC_KEY_6,                       -1, -1
6042   },
6043   {
6044     Xkey_7,                             TRUE,   FALSE,
6045     EL_EMC_KEY_7,                       -1, -1
6046   },
6047   {
6048     Xkey_8,                             TRUE,   FALSE,
6049     EL_EMC_KEY_8,                       -1, -1
6050   },
6051   {
6052     Xwind_n,                            TRUE,   FALSE,
6053     EL_BALLOON_SWITCH_UP,               -1, -1
6054   },
6055   {
6056     Xwind_e,                            TRUE,   FALSE,
6057     EL_BALLOON_SWITCH_RIGHT,            -1, -1
6058   },
6059   {
6060     Xwind_s,                            TRUE,   FALSE,
6061     EL_BALLOON_SWITCH_DOWN,             -1, -1
6062   },
6063   {
6064     Xwind_w,                            TRUE,   FALSE,
6065     EL_BALLOON_SWITCH_LEFT,             -1, -1
6066   },
6067   {
6068     Xwind_nesw,                         TRUE,   FALSE,
6069     EL_BALLOON_SWITCH_ANY,              -1, -1
6070   },
6071   {
6072     Xwind_stop,                         TRUE,   FALSE,
6073     EL_BALLOON_SWITCH_NONE,             -1, -1
6074   },
6075   {
6076     Xexit,                              TRUE,   FALSE,
6077     EL_EM_EXIT_CLOSED,                  -1, -1
6078   },
6079   {
6080     Xexit_1,                            TRUE,   FALSE,
6081     EL_EM_EXIT_OPEN,                    -1, -1
6082   },
6083   {
6084     Xexit_2,                            FALSE,  FALSE,
6085     EL_EM_EXIT_OPEN,                    -1, -1
6086   },
6087   {
6088     Xexit_3,                            FALSE,  FALSE,
6089     EL_EM_EXIT_OPEN,                    -1, -1
6090   },
6091   {
6092     Xdynamite,                          TRUE,   FALSE,
6093     EL_EM_DYNAMITE,                     -1, -1
6094   },
6095   {
6096     Ydynamite_eat,                      FALSE,  FALSE,
6097     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
6098   },
6099   {
6100     Xdynamite_1,                        TRUE,   FALSE,
6101     EL_EM_DYNAMITE_ACTIVE,              -1, -1
6102   },
6103   {
6104     Xdynamite_2,                        FALSE,  FALSE,
6105     EL_EM_DYNAMITE_ACTIVE,              -1, -1
6106   },
6107   {
6108     Xdynamite_3,                        FALSE,  FALSE,
6109     EL_EM_DYNAMITE_ACTIVE,              -1, -1
6110   },
6111   {
6112     Xdynamite_4,                        FALSE,  FALSE,
6113     EL_EM_DYNAMITE_ACTIVE,              -1, -1
6114   },
6115   {
6116     Xbumper,                            TRUE,   FALSE,
6117     EL_EMC_SPRING_BUMPER,               -1, -1
6118   },
6119   {
6120     XbumperB,                           FALSE,  FALSE,
6121     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
6122   },
6123   {
6124     Xwheel,                             TRUE,   FALSE,
6125     EL_ROBOT_WHEEL,                     -1, -1
6126   },
6127   {
6128     XwheelB,                            FALSE,  FALSE,
6129     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
6130   },
6131   {
6132     Xswitch,                            TRUE,   FALSE,
6133     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
6134   },
6135   {
6136     XswitchB,                           FALSE,  FALSE,
6137     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
6138   },
6139   {
6140     Xsand,                              TRUE,   FALSE,
6141     EL_QUICKSAND_EMPTY,                 -1, -1
6142   },
6143   {
6144     Xsand_stone,                        TRUE,   FALSE,
6145     EL_QUICKSAND_FULL,                  -1, -1
6146   },
6147   {
6148     Xsand_stonein_1,                    FALSE,  TRUE,
6149     EL_ROCK,                            ACTION_FILLING, -1
6150   },
6151   {
6152     Xsand_stonein_2,                    FALSE,  TRUE,
6153     EL_ROCK,                            ACTION_FILLING, -1
6154   },
6155   {
6156     Xsand_stonein_3,                    FALSE,  TRUE,
6157     EL_ROCK,                            ACTION_FILLING, -1
6158   },
6159   {
6160     Xsand_stonein_4,                    FALSE,  TRUE,
6161     EL_ROCK,                            ACTION_FILLING, -1
6162   },
6163 #if 1
6164   {
6165     Xsand_stonesand_1,                  FALSE,  FALSE,
6166     EL_QUICKSAND_EMPTYING,              -1, -1
6167   },
6168   {
6169     Xsand_stonesand_2,                  FALSE,  FALSE,
6170     EL_QUICKSAND_EMPTYING,              -1, -1
6171   },
6172   {
6173     Xsand_stonesand_3,                  FALSE,  FALSE,
6174     EL_QUICKSAND_EMPTYING,              -1, -1
6175   },
6176   {
6177     Xsand_stonesand_4,                  FALSE,  FALSE,
6178     EL_QUICKSAND_EMPTYING,              -1, -1
6179   },
6180   {
6181     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
6182     EL_QUICKSAND_EMPTYING,              -1, -1
6183   },
6184   {
6185     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
6186     EL_QUICKSAND_EMPTYING,              -1, -1
6187   },
6188 #else
6189   {
6190     Xsand_stonesand_1,                  FALSE,  FALSE,
6191     EL_QUICKSAND_FULL,                  -1, -1
6192   },
6193   {
6194     Xsand_stonesand_2,                  FALSE,  FALSE,
6195     EL_QUICKSAND_FULL,                  -1, -1
6196   },
6197   {
6198     Xsand_stonesand_3,                  FALSE,  FALSE,
6199     EL_QUICKSAND_FULL,                  -1, -1
6200   },
6201   {
6202     Xsand_stonesand_4,                  FALSE,  FALSE,
6203     EL_QUICKSAND_FULL,                  -1, -1
6204   },
6205 #endif
6206   {
6207     Xsand_stoneout_1,                   FALSE,  FALSE,
6208     EL_ROCK,                            ACTION_EMPTYING, -1
6209   },
6210   {
6211     Xsand_stoneout_2,                   FALSE,  FALSE,
6212     EL_ROCK,                            ACTION_EMPTYING, -1
6213   },
6214 #if 1
6215   {
6216     Xsand_sandstone_1,                  FALSE,  FALSE,
6217     EL_QUICKSAND_FILLING,               -1, -1
6218   },
6219   {
6220     Xsand_sandstone_2,                  FALSE,  FALSE,
6221     EL_QUICKSAND_FILLING,               -1, -1
6222   },
6223   {
6224     Xsand_sandstone_3,                  FALSE,  FALSE,
6225     EL_QUICKSAND_FILLING,               -1, -1
6226   },
6227   {
6228     Xsand_sandstone_4,                  FALSE,  FALSE,
6229     EL_QUICKSAND_FILLING,               -1, -1
6230   },
6231 #else
6232   {
6233     Xsand_sandstone_1,                  FALSE,  FALSE,
6234     EL_QUICKSAND_FULL,                  -1, -1
6235   },
6236   {
6237     Xsand_sandstone_2,                  FALSE,  FALSE,
6238     EL_QUICKSAND_FULL,                  -1, -1
6239   },
6240   {
6241     Xsand_sandstone_3,                  FALSE,  FALSE,
6242     EL_QUICKSAND_FULL,                  -1, -1
6243   },
6244   {
6245     Xsand_sandstone_4,                  FALSE,  FALSE,
6246     EL_QUICKSAND_FULL,                  -1, -1
6247   },
6248 #endif
6249   {
6250     Xplant,                             TRUE,   FALSE,
6251     EL_EMC_PLANT,                       -1, -1
6252   },
6253   {
6254     Yplant,                             FALSE,  FALSE,
6255     EL_EMC_PLANT,                       -1, -1
6256   },
6257   {
6258     Xlenses,                            TRUE,   FALSE,
6259     EL_EMC_LENSES,                      -1, -1
6260   },
6261   {
6262     Xmagnify,                           TRUE,   FALSE,
6263     EL_EMC_MAGNIFIER,                   -1, -1
6264   },
6265   {
6266     Xdripper,                           TRUE,   FALSE,
6267     EL_EMC_DRIPPER,                     -1, -1
6268   },
6269   {
6270     XdripperB,                          FALSE,  FALSE,
6271     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
6272   },
6273   {
6274     Xfake_blank,                        TRUE,   FALSE,
6275     EL_INVISIBLE_WALL,                  -1, -1
6276   },
6277   {
6278     Xfake_blankB,                       FALSE,  FALSE,
6279     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
6280   },
6281   {
6282     Xfake_grass,                        TRUE,   FALSE,
6283     EL_EMC_FAKE_GRASS,                  -1, -1
6284   },
6285   {
6286     Xfake_grassB,                       FALSE,  FALSE,
6287     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
6288   },
6289   {
6290     Xfake_door_1,                       TRUE,   FALSE,
6291     EL_EM_GATE_1_GRAY,                  -1, -1
6292   },
6293   {
6294     Xfake_door_2,                       TRUE,   FALSE,
6295     EL_EM_GATE_2_GRAY,                  -1, -1
6296   },
6297   {
6298     Xfake_door_3,                       TRUE,   FALSE,
6299     EL_EM_GATE_3_GRAY,                  -1, -1
6300   },
6301   {
6302     Xfake_door_4,                       TRUE,   FALSE,
6303     EL_EM_GATE_4_GRAY,                  -1, -1
6304   },
6305   {
6306     Xfake_door_5,                       TRUE,   FALSE,
6307     EL_EMC_GATE_5_GRAY,                 -1, -1
6308   },
6309   {
6310     Xfake_door_6,                       TRUE,   FALSE,
6311     EL_EMC_GATE_6_GRAY,                 -1, -1
6312   },
6313   {
6314     Xfake_door_7,                       TRUE,   FALSE,
6315     EL_EMC_GATE_7_GRAY,                 -1, -1
6316   },
6317   {
6318     Xfake_door_8,                       TRUE,   FALSE,
6319     EL_EMC_GATE_8_GRAY,                 -1, -1
6320   },
6321   {
6322     Xfake_acid_1,                       TRUE,   FALSE,
6323     EL_EMC_FAKE_ACID,                   -1, -1
6324   },
6325   {
6326     Xfake_acid_2,                       FALSE,  FALSE,
6327     EL_EMC_FAKE_ACID,                   -1, -1
6328   },
6329   {
6330     Xfake_acid_3,                       FALSE,  FALSE,
6331     EL_EMC_FAKE_ACID,                   -1, -1
6332   },
6333   {
6334     Xfake_acid_4,                       FALSE,  FALSE,
6335     EL_EMC_FAKE_ACID,                   -1, -1
6336   },
6337   {
6338     Xfake_acid_5,                       FALSE,  FALSE,
6339     EL_EMC_FAKE_ACID,                   -1, -1
6340   },
6341   {
6342     Xfake_acid_6,                       FALSE,  FALSE,
6343     EL_EMC_FAKE_ACID,                   -1, -1
6344   },
6345   {
6346     Xfake_acid_7,                       FALSE,  FALSE,
6347     EL_EMC_FAKE_ACID,                   -1, -1
6348   },
6349   {
6350     Xfake_acid_8,                       FALSE,  FALSE,
6351     EL_EMC_FAKE_ACID,                   -1, -1
6352   },
6353   {
6354     Xsteel_1,                           TRUE,   FALSE,
6355     EL_STEELWALL,                       -1, -1
6356   },
6357   {
6358     Xsteel_2,                           TRUE,   FALSE,
6359     EL_EMC_STEELWALL_2,                 -1, -1
6360   },
6361   {
6362     Xsteel_3,                           TRUE,   FALSE,
6363     EL_EMC_STEELWALL_3,                 -1, -1
6364   },
6365   {
6366     Xsteel_4,                           TRUE,   FALSE,
6367     EL_EMC_STEELWALL_4,                 -1, -1
6368   },
6369   {
6370     Xwall_1,                            TRUE,   FALSE,
6371     EL_WALL,                            -1, -1
6372   },
6373   {
6374     Xwall_2,                            TRUE,   FALSE,
6375     EL_EMC_WALL_14,                     -1, -1
6376   },
6377   {
6378     Xwall_3,                            TRUE,   FALSE,
6379     EL_EMC_WALL_15,                     -1, -1
6380   },
6381   {
6382     Xwall_4,                            TRUE,   FALSE,
6383     EL_EMC_WALL_16,                     -1, -1
6384   },
6385   {
6386     Xround_wall_1,                      TRUE,   FALSE,
6387     EL_WALL_SLIPPERY,                   -1, -1
6388   },
6389   {
6390     Xround_wall_2,                      TRUE,   FALSE,
6391     EL_EMC_WALL_SLIPPERY_2,             -1, -1
6392   },
6393   {
6394     Xround_wall_3,                      TRUE,   FALSE,
6395     EL_EMC_WALL_SLIPPERY_3,             -1, -1
6396   },
6397   {
6398     Xround_wall_4,                      TRUE,   FALSE,
6399     EL_EMC_WALL_SLIPPERY_4,             -1, -1
6400   },
6401   {
6402     Xdecor_1,                           TRUE,   FALSE,
6403     EL_EMC_WALL_8,                      -1, -1
6404   },
6405   {
6406     Xdecor_2,                           TRUE,   FALSE,
6407     EL_EMC_WALL_6,                      -1, -1
6408   },
6409   {
6410     Xdecor_3,                           TRUE,   FALSE,
6411     EL_EMC_WALL_4,                      -1, -1
6412   },
6413   {
6414     Xdecor_4,                           TRUE,   FALSE,
6415     EL_EMC_WALL_7,                      -1, -1
6416   },
6417   {
6418     Xdecor_5,                           TRUE,   FALSE,
6419     EL_EMC_WALL_5,                      -1, -1
6420   },
6421   {
6422     Xdecor_6,                           TRUE,   FALSE,
6423     EL_EMC_WALL_9,                      -1, -1
6424   },
6425   {
6426     Xdecor_7,                           TRUE,   FALSE,
6427     EL_EMC_WALL_10,                     -1, -1
6428   },
6429   {
6430     Xdecor_8,                           TRUE,   FALSE,
6431     EL_EMC_WALL_1,                      -1, -1
6432   },
6433   {
6434     Xdecor_9,                           TRUE,   FALSE,
6435     EL_EMC_WALL_2,                      -1, -1
6436   },
6437   {
6438     Xdecor_10,                          TRUE,   FALSE,
6439     EL_EMC_WALL_3,                      -1, -1
6440   },
6441   {
6442     Xdecor_11,                          TRUE,   FALSE,
6443     EL_EMC_WALL_11,                     -1, -1
6444   },
6445   {
6446     Xdecor_12,                          TRUE,   FALSE,
6447     EL_EMC_WALL_12,                     -1, -1
6448   },
6449   {
6450     Xalpha_0,                           TRUE,   FALSE,
6451     EL_CHAR('0'),                       -1, -1
6452   },
6453   {
6454     Xalpha_1,                           TRUE,   FALSE,
6455     EL_CHAR('1'),                       -1, -1
6456   },
6457   {
6458     Xalpha_2,                           TRUE,   FALSE,
6459     EL_CHAR('2'),                       -1, -1
6460   },
6461   {
6462     Xalpha_3,                           TRUE,   FALSE,
6463     EL_CHAR('3'),                       -1, -1
6464   },
6465   {
6466     Xalpha_4,                           TRUE,   FALSE,
6467     EL_CHAR('4'),                       -1, -1
6468   },
6469   {
6470     Xalpha_5,                           TRUE,   FALSE,
6471     EL_CHAR('5'),                       -1, -1
6472   },
6473   {
6474     Xalpha_6,                           TRUE,   FALSE,
6475     EL_CHAR('6'),                       -1, -1
6476   },
6477   {
6478     Xalpha_7,                           TRUE,   FALSE,
6479     EL_CHAR('7'),                       -1, -1
6480   },
6481   {
6482     Xalpha_8,                           TRUE,   FALSE,
6483     EL_CHAR('8'),                       -1, -1
6484   },
6485   {
6486     Xalpha_9,                           TRUE,   FALSE,
6487     EL_CHAR('9'),                       -1, -1
6488   },
6489   {
6490     Xalpha_excla,                       TRUE,   FALSE,
6491     EL_CHAR('!'),                       -1, -1
6492   },
6493   {
6494     Xalpha_quote,                       TRUE,   FALSE,
6495     EL_CHAR('"'),                       -1, -1
6496   },
6497   {
6498     Xalpha_comma,                       TRUE,   FALSE,
6499     EL_CHAR(','),                       -1, -1
6500   },
6501   {
6502     Xalpha_minus,                       TRUE,   FALSE,
6503     EL_CHAR('-'),                       -1, -1
6504   },
6505   {
6506     Xalpha_perio,                       TRUE,   FALSE,
6507     EL_CHAR('.'),                       -1, -1
6508   },
6509   {
6510     Xalpha_colon,                       TRUE,   FALSE,
6511     EL_CHAR(':'),                       -1, -1
6512   },
6513   {
6514     Xalpha_quest,                       TRUE,   FALSE,
6515     EL_CHAR('?'),                       -1, -1
6516   },
6517   {
6518     Xalpha_a,                           TRUE,   FALSE,
6519     EL_CHAR('A'),                       -1, -1
6520   },
6521   {
6522     Xalpha_b,                           TRUE,   FALSE,
6523     EL_CHAR('B'),                       -1, -1
6524   },
6525   {
6526     Xalpha_c,                           TRUE,   FALSE,
6527     EL_CHAR('C'),                       -1, -1
6528   },
6529   {
6530     Xalpha_d,                           TRUE,   FALSE,
6531     EL_CHAR('D'),                       -1, -1
6532   },
6533   {
6534     Xalpha_e,                           TRUE,   FALSE,
6535     EL_CHAR('E'),                       -1, -1
6536   },
6537   {
6538     Xalpha_f,                           TRUE,   FALSE,
6539     EL_CHAR('F'),                       -1, -1
6540   },
6541   {
6542     Xalpha_g,                           TRUE,   FALSE,
6543     EL_CHAR('G'),                       -1, -1
6544   },
6545   {
6546     Xalpha_h,                           TRUE,   FALSE,
6547     EL_CHAR('H'),                       -1, -1
6548   },
6549   {
6550     Xalpha_i,                           TRUE,   FALSE,
6551     EL_CHAR('I'),                       -1, -1
6552   },
6553   {
6554     Xalpha_j,                           TRUE,   FALSE,
6555     EL_CHAR('J'),                       -1, -1
6556   },
6557   {
6558     Xalpha_k,                           TRUE,   FALSE,
6559     EL_CHAR('K'),                       -1, -1
6560   },
6561   {
6562     Xalpha_l,                           TRUE,   FALSE,
6563     EL_CHAR('L'),                       -1, -1
6564   },
6565   {
6566     Xalpha_m,                           TRUE,   FALSE,
6567     EL_CHAR('M'),                       -1, -1
6568   },
6569   {
6570     Xalpha_n,                           TRUE,   FALSE,
6571     EL_CHAR('N'),                       -1, -1
6572   },
6573   {
6574     Xalpha_o,                           TRUE,   FALSE,
6575     EL_CHAR('O'),                       -1, -1
6576   },
6577   {
6578     Xalpha_p,                           TRUE,   FALSE,
6579     EL_CHAR('P'),                       -1, -1
6580   },
6581   {
6582     Xalpha_q,                           TRUE,   FALSE,
6583     EL_CHAR('Q'),                       -1, -1
6584   },
6585   {
6586     Xalpha_r,                           TRUE,   FALSE,
6587     EL_CHAR('R'),                       -1, -1
6588   },
6589   {
6590     Xalpha_s,                           TRUE,   FALSE,
6591     EL_CHAR('S'),                       -1, -1
6592   },
6593   {
6594     Xalpha_t,                           TRUE,   FALSE,
6595     EL_CHAR('T'),                       -1, -1
6596   },
6597   {
6598     Xalpha_u,                           TRUE,   FALSE,
6599     EL_CHAR('U'),                       -1, -1
6600   },
6601   {
6602     Xalpha_v,                           TRUE,   FALSE,
6603     EL_CHAR('V'),                       -1, -1
6604   },
6605   {
6606     Xalpha_w,                           TRUE,   FALSE,
6607     EL_CHAR('W'),                       -1, -1
6608   },
6609   {
6610     Xalpha_x,                           TRUE,   FALSE,
6611     EL_CHAR('X'),                       -1, -1
6612   },
6613   {
6614     Xalpha_y,                           TRUE,   FALSE,
6615     EL_CHAR('Y'),                       -1, -1
6616   },
6617   {
6618     Xalpha_z,                           TRUE,   FALSE,
6619     EL_CHAR('Z'),                       -1, -1
6620   },
6621   {
6622     Xalpha_arrow_e,                     TRUE,   FALSE,
6623     EL_CHAR('>'),                       -1, -1
6624   },
6625   {
6626     Xalpha_arrow_w,                     TRUE,   FALSE,
6627     EL_CHAR('<'),                       -1, -1
6628   },
6629   {
6630     Xalpha_copyr,                       TRUE,   FALSE,
6631     EL_CHAR('©'),                       -1, -1
6632   },
6633
6634   {
6635     Xboom_bug,                          FALSE,  FALSE,
6636     EL_BUG,                             ACTION_EXPLODING, -1
6637   },
6638   {
6639     Xboom_bomb,                         FALSE,  FALSE,
6640     EL_BOMB,                            ACTION_EXPLODING, -1
6641   },
6642   {
6643     Xboom_android,                      FALSE,  FALSE,
6644     EL_EMC_ANDROID,                     ACTION_OTHER, -1
6645   },
6646   {
6647     Xboom_1,                            FALSE,  FALSE,
6648     EL_DEFAULT,                         ACTION_EXPLODING, -1
6649   },
6650   {
6651     Xboom_2,                            FALSE,  FALSE,
6652     EL_DEFAULT,                         ACTION_EXPLODING, -1
6653   },
6654   {
6655     Znormal,                            FALSE,  FALSE,
6656     EL_EMPTY,                           -1, -1
6657   },
6658   {
6659     Zdynamite,                          FALSE,  FALSE,
6660     EL_EMPTY,                           -1, -1
6661   },
6662   {
6663     Zplayer,                            FALSE,  FALSE,
6664     EL_EMPTY,                           -1, -1
6665   },
6666   {
6667     ZBORDER,                            FALSE,  FALSE,
6668     EL_EMPTY,                           -1, -1
6669   },
6670
6671   {
6672     -1,                                 FALSE,  FALSE,
6673     -1,                                 -1, -1
6674   }
6675 };
6676
6677 static struct Mapping_EM_to_RND_player
6678 {
6679   int action_em;
6680   int player_nr;
6681
6682   int element_rnd;
6683   int action;
6684   int direction;
6685 }
6686 em_player_mapping_list[] =
6687 {
6688   {
6689     SPR_walk + 0,                       0,
6690     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
6691   },
6692   {
6693     SPR_walk + 1,                       0,
6694     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
6695   },
6696   {
6697     SPR_walk + 2,                       0,
6698     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
6699   },
6700   {
6701     SPR_walk + 3,                       0,
6702     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
6703   },
6704   {
6705     SPR_push + 0,                       0,
6706     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
6707   },
6708   {
6709     SPR_push + 1,                       0,
6710     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
6711   },
6712   {
6713     SPR_push + 2,                       0,
6714     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
6715   },
6716   {
6717     SPR_push + 3,                       0,
6718     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
6719   },
6720   {
6721     SPR_spray + 0,                      0,
6722     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
6723   },
6724   {
6725     SPR_spray + 1,                      0,
6726     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6727   },
6728   {
6729     SPR_spray + 2,                      0,
6730     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
6731   },
6732   {
6733     SPR_spray + 3,                      0,
6734     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
6735   },
6736   {
6737     SPR_walk + 0,                       1,
6738     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
6739   },
6740   {
6741     SPR_walk + 1,                       1,
6742     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
6743   },
6744   {
6745     SPR_walk + 2,                       1,
6746     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
6747   },
6748   {
6749     SPR_walk + 3,                       1,
6750     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
6751   },
6752   {
6753     SPR_push + 0,                       1,
6754     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
6755   },
6756   {
6757     SPR_push + 1,                       1,
6758     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
6759   },
6760   {
6761     SPR_push + 2,                       1,
6762     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
6763   },
6764   {
6765     SPR_push + 3,                       1,
6766     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
6767   },
6768   {
6769     SPR_spray + 0,                      1,
6770     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
6771   },
6772   {
6773     SPR_spray + 1,                      1,
6774     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6775   },
6776   {
6777     SPR_spray + 2,                      1,
6778     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
6779   },
6780   {
6781     SPR_spray + 3,                      1,
6782     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
6783   },
6784   {
6785     SPR_still,                          0,
6786     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
6787   },
6788   {
6789     SPR_still,                          1,
6790     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
6791   },
6792   {
6793     SPR_walk + 0,                       2,
6794     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
6795   },
6796   {
6797     SPR_walk + 1,                       2,
6798     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
6799   },
6800   {
6801     SPR_walk + 2,                       2,
6802     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
6803   },
6804   {
6805     SPR_walk + 3,                       2,
6806     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
6807   },
6808   {
6809     SPR_push + 0,                       2,
6810     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
6811   },
6812   {
6813     SPR_push + 1,                       2,
6814     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
6815   },
6816   {
6817     SPR_push + 2,                       2,
6818     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
6819   },
6820   {
6821     SPR_push + 3,                       2,
6822     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
6823   },
6824   {
6825     SPR_spray + 0,                      2,
6826     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
6827   },
6828   {
6829     SPR_spray + 1,                      2,
6830     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6831   },
6832   {
6833     SPR_spray + 2,                      2,
6834     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
6835   },
6836   {
6837     SPR_spray + 3,                      2,
6838     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
6839   },
6840   {
6841     SPR_walk + 0,                       3,
6842     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
6843   },
6844   {
6845     SPR_walk + 1,                       3,
6846     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
6847   },
6848   {
6849     SPR_walk + 2,                       3,
6850     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
6851   },
6852   {
6853     SPR_walk + 3,                       3,
6854     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
6855   },
6856   {
6857     SPR_push + 0,                       3,
6858     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
6859   },
6860   {
6861     SPR_push + 1,                       3,
6862     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
6863   },
6864   {
6865     SPR_push + 2,                       3,
6866     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
6867   },
6868   {
6869     SPR_push + 3,                       3,
6870     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
6871   },
6872   {
6873     SPR_spray + 0,                      3,
6874     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
6875   },
6876   {
6877     SPR_spray + 1,                      3,
6878     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6879   },
6880   {
6881     SPR_spray + 2,                      3,
6882     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
6883   },
6884   {
6885     SPR_spray + 3,                      3,
6886     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
6887   },
6888   {
6889     SPR_still,                          2,
6890     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
6891   },
6892   {
6893     SPR_still,                          3,
6894     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
6895   },
6896
6897   {
6898     -1,                                 -1,
6899     -1,                                 -1, -1
6900   }
6901 };
6902
6903 int map_element_RND_to_EM(int element_rnd)
6904 {
6905   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6906   static boolean mapping_initialized = FALSE;
6907
6908   if (!mapping_initialized)
6909   {
6910     int i;
6911
6912     /* return "Xalpha_quest" for all undefined elements in mapping array */
6913     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6914       mapping_RND_to_EM[i] = Xalpha_quest;
6915
6916     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6917       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6918         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6919           em_object_mapping_list[i].element_em;
6920
6921     mapping_initialized = TRUE;
6922   }
6923
6924   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6925     return mapping_RND_to_EM[element_rnd];
6926
6927   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6928
6929   return EL_UNKNOWN;
6930 }
6931
6932 int map_element_EM_to_RND(int element_em)
6933 {
6934   static unsigned short mapping_EM_to_RND[TILE_MAX];
6935   static boolean mapping_initialized = FALSE;
6936
6937   if (!mapping_initialized)
6938   {
6939     int i;
6940
6941     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6942     for (i = 0; i < TILE_MAX; i++)
6943       mapping_EM_to_RND[i] = EL_UNKNOWN;
6944
6945     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6946       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6947         em_object_mapping_list[i].element_rnd;
6948
6949     mapping_initialized = TRUE;
6950   }
6951
6952   if (element_em >= 0 && element_em < TILE_MAX)
6953     return mapping_EM_to_RND[element_em];
6954
6955   Error(ERR_WARN, "invalid EM level element %d", element_em);
6956
6957   return EL_UNKNOWN;
6958 }
6959
6960 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6961 {
6962   struct LevelInfo_EM *level_em = level->native_em_level;
6963   struct LEVEL *lev = level_em->lev;
6964   int i, j;
6965
6966   for (i = 0; i < TILE_MAX; i++)
6967     lev->android_array[i] = Xblank;
6968
6969   for (i = 0; i < level->num_android_clone_elements; i++)
6970   {
6971     int element_rnd = level->android_clone_element[i];
6972     int element_em = map_element_RND_to_EM(element_rnd);
6973
6974     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6975       if (em_object_mapping_list[j].element_rnd == element_rnd)
6976         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6977   }
6978 }
6979
6980 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6981 {
6982   struct LevelInfo_EM *level_em = level->native_em_level;
6983   struct LEVEL *lev = level_em->lev;
6984   int i, j;
6985
6986   level->num_android_clone_elements = 0;
6987
6988   for (i = 0; i < TILE_MAX; i++)
6989   {
6990     int element_em = lev->android_array[i];
6991     int element_rnd;
6992     boolean element_found = FALSE;
6993
6994     if (element_em == Xblank)
6995       continue;
6996
6997     element_rnd = map_element_EM_to_RND(element_em);
6998
6999     for (j = 0; j < level->num_android_clone_elements; j++)
7000       if (level->android_clone_element[j] == element_rnd)
7001         element_found = TRUE;
7002
7003     if (!element_found)
7004     {
7005       level->android_clone_element[level->num_android_clone_elements++] =
7006         element_rnd;
7007
7008       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7009         break;
7010     }
7011   }
7012
7013   if (level->num_android_clone_elements == 0)
7014   {
7015     level->num_android_clone_elements = 1;
7016     level->android_clone_element[0] = EL_EMPTY;
7017   }
7018 }
7019
7020 int map_direction_RND_to_EM(int direction)
7021 {
7022   return (direction == MV_UP    ? 0 :
7023           direction == MV_RIGHT ? 1 :
7024           direction == MV_DOWN  ? 2 :
7025           direction == MV_LEFT  ? 3 :
7026           -1);
7027 }
7028
7029 int map_direction_EM_to_RND(int direction)
7030 {
7031   return (direction == 0 ? MV_UP    :
7032           direction == 1 ? MV_RIGHT :
7033           direction == 2 ? MV_DOWN  :
7034           direction == 3 ? MV_LEFT  :
7035           MV_NONE);
7036 }
7037
7038 int map_element_RND_to_SP(int element_rnd)
7039 {
7040   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
7041
7042   if (element_rnd >= EL_SP_START &&
7043       element_rnd <= EL_SP_END)
7044     element_sp = element_rnd - EL_SP_START;
7045   else if (element_rnd == EL_EMPTY_SPACE)
7046     element_sp = 0x00;
7047   else if (element_rnd == EL_INVISIBLE_WALL)
7048     element_sp = 0x28;
7049
7050   return element_sp;
7051 }
7052
7053 int map_element_SP_to_RND(int element_sp)
7054 {
7055   int element_rnd = EL_UNKNOWN;
7056
7057   if (element_sp >= 0x00 &&
7058       element_sp <= 0x27)
7059     element_rnd = EL_SP_START + element_sp;
7060   else if (element_sp == 0x28)
7061     element_rnd = EL_INVISIBLE_WALL;
7062
7063   return element_rnd;
7064 }
7065
7066 int map_action_SP_to_RND(int action_sp)
7067 {
7068   switch (action_sp)
7069   {
7070     case actActive:             return ACTION_ACTIVE;
7071     case actImpact:             return ACTION_IMPACT;
7072     case actExploding:          return ACTION_EXPLODING;
7073     case actDigging:            return ACTION_DIGGING;
7074     case actSnapping:           return ACTION_SNAPPING;
7075     case actCollecting:         return ACTION_COLLECTING;
7076     case actPassing:            return ACTION_PASSING;
7077     case actPushing:            return ACTION_PUSHING;
7078     case actDropping:           return ACTION_DROPPING;
7079
7080     default:                    return ACTION_DEFAULT;
7081   }
7082 }
7083
7084 int get_next_element(int element)
7085 {
7086   switch (element)
7087   {
7088     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
7089     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
7090     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
7091     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
7092     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
7093     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
7094     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
7095     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
7096     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
7097     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
7098     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
7099
7100     default:                            return element;
7101   }
7102 }
7103
7104 #if 0
7105 int el_act_dir2img(int element, int action, int direction)
7106 {
7107   element = GFX_ELEMENT(element);
7108
7109   if (direction == MV_NONE)
7110     return element_info[element].graphic[action];
7111
7112   direction = MV_DIR_TO_BIT(direction);
7113
7114   return element_info[element].direction_graphic[action][direction];
7115 }
7116 #else
7117 int el_act_dir2img(int element, int action, int direction)
7118 {
7119   element = GFX_ELEMENT(element);
7120   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7121
7122   /* direction_graphic[][] == graphic[] for undefined direction graphics */
7123   return element_info[element].direction_graphic[action][direction];
7124 }
7125 #endif
7126
7127 #if 0
7128 static int el_act_dir2crm(int element, int action, int direction)
7129 {
7130   element = GFX_ELEMENT(element);
7131
7132   if (direction == MV_NONE)
7133     return element_info[element].crumbled[action];
7134
7135   direction = MV_DIR_TO_BIT(direction);
7136
7137   return element_info[element].direction_crumbled[action][direction];
7138 }
7139 #else
7140 static int el_act_dir2crm(int element, int action, int direction)
7141 {
7142   element = GFX_ELEMENT(element);
7143   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7144
7145   /* direction_graphic[][] == graphic[] for undefined direction graphics */
7146   return element_info[element].direction_crumbled[action][direction];
7147 }
7148 #endif
7149
7150 int el_act2img(int element, int action)
7151 {
7152   element = GFX_ELEMENT(element);
7153
7154   return element_info[element].graphic[action];
7155 }
7156
7157 int el_act2crm(int element, int action)
7158 {
7159   element = GFX_ELEMENT(element);
7160
7161   return element_info[element].crumbled[action];
7162 }
7163
7164 int el_dir2img(int element, int direction)
7165 {
7166   element = GFX_ELEMENT(element);
7167
7168   return el_act_dir2img(element, ACTION_DEFAULT, direction);
7169 }
7170
7171 int el2baseimg(int element)
7172 {
7173   return element_info[element].graphic[ACTION_DEFAULT];
7174 }
7175
7176 int el2img(int element)
7177 {
7178   element = GFX_ELEMENT(element);
7179
7180   return element_info[element].graphic[ACTION_DEFAULT];
7181 }
7182
7183 int el2edimg(int element)
7184 {
7185   element = GFX_ELEMENT(element);
7186
7187   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
7188 }
7189
7190 int el2preimg(int element)
7191 {
7192   element = GFX_ELEMENT(element);
7193
7194   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
7195 }
7196
7197 int el2panelimg(int element)
7198 {
7199   element = GFX_ELEMENT(element);
7200
7201   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
7202 }
7203
7204 int font2baseimg(int font_nr)
7205 {
7206   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
7207 }
7208
7209 int getBeltNrFromBeltElement(int element)
7210 {
7211   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
7212           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
7213           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
7214 }
7215
7216 int getBeltNrFromBeltActiveElement(int element)
7217 {
7218   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
7219           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
7220           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
7221 }
7222
7223 int getBeltNrFromBeltSwitchElement(int element)
7224 {
7225   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
7226           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
7227           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
7228 }
7229
7230 int getBeltDirNrFromBeltElement(int element)
7231 {
7232   static int belt_base_element[4] =
7233   {
7234     EL_CONVEYOR_BELT_1_LEFT,
7235     EL_CONVEYOR_BELT_2_LEFT,
7236     EL_CONVEYOR_BELT_3_LEFT,
7237     EL_CONVEYOR_BELT_4_LEFT
7238   };
7239
7240   int belt_nr = getBeltNrFromBeltElement(element);
7241   int belt_dir_nr = element - belt_base_element[belt_nr];
7242
7243   return (belt_dir_nr % 3);
7244 }
7245
7246 int getBeltDirNrFromBeltSwitchElement(int element)
7247 {
7248   static int belt_base_element[4] =
7249   {
7250     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7251     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7252     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7253     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7254   };
7255
7256   int belt_nr = getBeltNrFromBeltSwitchElement(element);
7257   int belt_dir_nr = element - belt_base_element[belt_nr];
7258
7259   return (belt_dir_nr % 3);
7260 }
7261
7262 int getBeltDirFromBeltElement(int element)
7263 {
7264   static int belt_move_dir[3] =
7265   {
7266     MV_LEFT,
7267     MV_NONE,
7268     MV_RIGHT
7269   };
7270
7271   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
7272
7273   return belt_move_dir[belt_dir_nr];
7274 }
7275
7276 int getBeltDirFromBeltSwitchElement(int element)
7277 {
7278   static int belt_move_dir[3] =
7279   {
7280     MV_LEFT,
7281     MV_NONE,
7282     MV_RIGHT
7283   };
7284
7285   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
7286
7287   return belt_move_dir[belt_dir_nr];
7288 }
7289
7290 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7291 {
7292   static int belt_base_element[4] =
7293   {
7294     EL_CONVEYOR_BELT_1_LEFT,
7295     EL_CONVEYOR_BELT_2_LEFT,
7296     EL_CONVEYOR_BELT_3_LEFT,
7297     EL_CONVEYOR_BELT_4_LEFT
7298   };
7299
7300   return belt_base_element[belt_nr] + belt_dir_nr;
7301 }
7302
7303 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7304 {
7305   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7306
7307   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7308 }
7309
7310 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
7311 {
7312   static int belt_base_element[4] =
7313   {
7314     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
7315     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
7316     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
7317     EL_CONVEYOR_BELT_4_SWITCH_LEFT
7318   };
7319
7320   return belt_base_element[belt_nr] + belt_dir_nr;
7321 }
7322
7323 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
7324 {
7325   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
7326
7327   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
7328 }
7329
7330 int getNumActivePlayers_EM()
7331 {
7332   int num_players = 0;
7333   int i;
7334
7335   if (!tape.playing)
7336     return -1;
7337
7338   for (i = 0; i < MAX_PLAYERS; i++)
7339     if (tape.player_participates[i])
7340       num_players++;
7341
7342   return num_players;
7343 }
7344
7345 int getGameFrameDelay_EM(int native_em_game_frame_delay)
7346 {
7347   int game_frame_delay_value;
7348
7349   game_frame_delay_value =
7350     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
7351      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
7352      GameFrameDelay);
7353
7354   if (tape.playing && tape.warp_forward && !tape.pausing)
7355     game_frame_delay_value = 0;
7356
7357   return game_frame_delay_value;
7358 }
7359
7360 unsigned int InitRND(int seed)
7361 {
7362   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
7363     return InitEngineRandom_EM(seed);
7364   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
7365     return InitEngineRandom_SP(seed);
7366   else
7367     return InitEngineRandom_RND(seed);
7368 }
7369
7370 #if 1
7371 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
7372 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
7373 #endif
7374
7375 inline static int get_effective_element_EM(int tile, int frame_em)
7376 {
7377   int element             = object_mapping[tile].element_rnd;
7378   int action              = object_mapping[tile].action;
7379   boolean is_backside     = object_mapping[tile].is_backside;
7380   boolean action_removing = (action == ACTION_DIGGING ||
7381                              action == ACTION_SNAPPING ||
7382                              action == ACTION_COLLECTING);
7383
7384   if (frame_em < 7)
7385   {
7386     switch (tile)
7387     {
7388       case Yacid_splash_eB:
7389       case Yacid_splash_wB:
7390         return (frame_em > 5 ? EL_EMPTY : element);
7391
7392 #if 0
7393         /* !!! FIX !!! */
7394       case Ydiamond_stone:
7395         //  if (!game.use_native_emc_graphics_engine)
7396         return EL_ROCK;
7397 #endif
7398
7399       default:
7400         return element;
7401     }
7402   }
7403   else  /* frame_em == 7 */
7404   {
7405     switch (tile)
7406     {
7407       case Yacid_splash_eB:
7408       case Yacid_splash_wB:
7409         return EL_EMPTY;
7410
7411       case Yemerald_stone:
7412         return EL_EMERALD;
7413
7414       case Ydiamond_stone:
7415         return EL_ROCK;
7416
7417       case Xdrip_stretch:
7418       case Xdrip_stretchB:
7419       case Ydrip_s1:
7420       case Ydrip_s1B:
7421       case Xball_1B:
7422       case Xball_2:
7423       case Xball_2B:
7424       case Yball_eat:
7425       case Ykey_1_eat:
7426       case Ykey_2_eat:
7427       case Ykey_3_eat:
7428       case Ykey_4_eat:
7429       case Ykey_5_eat:
7430       case Ykey_6_eat:
7431       case Ykey_7_eat:
7432       case Ykey_8_eat:
7433       case Ylenses_eat:
7434       case Ymagnify_eat:
7435       case Ygrass_eat:
7436       case Ydirt_eat:
7437       case Xsand_stonein_1:
7438       case Xsand_stonein_2:
7439       case Xsand_stonein_3:
7440       case Xsand_stonein_4:
7441         return element;
7442
7443       default:
7444         return (is_backside || action_removing ? EL_EMPTY : element);
7445     }
7446   }
7447 }
7448
7449 inline static boolean check_linear_animation_EM(int tile)
7450 {
7451   switch (tile)
7452   {
7453     case Xsand_stonesand_1:
7454     case Xsand_stonesand_quickout_1:
7455     case Xsand_sandstone_1:
7456     case Xsand_stonein_1:
7457     case Xsand_stoneout_1:
7458     case Xboom_1:
7459     case Xdynamite_1:
7460     case Ybug_w_n:
7461     case Ybug_n_e:
7462     case Ybug_e_s:
7463     case Ybug_s_w:
7464     case Ybug_e_n:
7465     case Ybug_s_e:
7466     case Ybug_w_s:
7467     case Ybug_n_w:
7468     case Ytank_w_n:
7469     case Ytank_n_e:
7470     case Ytank_e_s:
7471     case Ytank_s_w:
7472     case Ytank_e_n:
7473     case Ytank_s_e:
7474     case Ytank_w_s:
7475     case Ytank_n_w:
7476 #if 1
7477     case Yacid_splash_eB:
7478     case Yacid_splash_wB:
7479     case Yemerald_stone:
7480 #endif
7481       return TRUE;
7482   }
7483
7484   return FALSE;
7485 }
7486
7487 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
7488                                             boolean has_crumbled_graphics,
7489                                             int crumbled, int sync_frame)
7490 {
7491   /* if element can be crumbled, but certain action graphics are just empty
7492      space (like instantly snapping sand to empty space in 1 frame), do not
7493      treat these empty space graphics as crumbled graphics in EMC engine */
7494   if (crumbled == IMG_EMPTY_SPACE)
7495     has_crumbled_graphics = FALSE;
7496
7497   if (has_crumbled_graphics)
7498   {
7499     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7500     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
7501                                            g_crumbled->anim_delay,
7502                                            g_crumbled->anim_mode,
7503                                            g_crumbled->anim_start_frame,
7504                                            sync_frame);
7505
7506     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
7507                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
7508
7509     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
7510
7511     g_em->has_crumbled_graphics = TRUE;
7512   }
7513   else
7514   {
7515     g_em->crumbled_bitmap = NULL;
7516     g_em->crumbled_src_x = 0;
7517     g_em->crumbled_src_y = 0;
7518     g_em->crumbled_border_size = 0;
7519
7520     g_em->has_crumbled_graphics = FALSE;
7521   }
7522 }
7523
7524 void ResetGfxAnimation_EM(int x, int y, int tile)
7525 {
7526   GfxFrame[x][y] = 0;
7527 }
7528
7529 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
7530                         int tile, int frame_em, int x, int y)
7531 {
7532   int action = object_mapping[tile].action;
7533 #if 1
7534   int direction = object_mapping[tile].direction;
7535   int effective_element = get_effective_element_EM(tile, frame_em);
7536   int graphic = (direction == MV_NONE ?
7537                  el_act2img(effective_element, action) :
7538                  el_act_dir2img(effective_element, action, direction));
7539   struct GraphicInfo *g = &graphic_info[graphic];
7540   int sync_frame;
7541 #endif
7542   boolean action_removing = (action == ACTION_DIGGING ||
7543                              action == ACTION_SNAPPING ||
7544                              action == ACTION_COLLECTING);
7545   boolean action_moving   = (action == ACTION_FALLING ||
7546                              action == ACTION_MOVING ||
7547                              action == ACTION_PUSHING ||
7548                              action == ACTION_EATING ||
7549                              action == ACTION_FILLING ||
7550                              action == ACTION_EMPTYING);
7551   boolean action_falling  = (action == ACTION_FALLING ||
7552                              action == ACTION_FILLING ||
7553                              action == ACTION_EMPTYING);
7554
7555   /* special case: graphic uses "2nd movement tile" and has defined
7556      7 frames for movement animation (or less) => use default graphic
7557      for last (8th) frame which ends the movement animation */
7558   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7559   {
7560     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
7561     graphic = (direction == MV_NONE ?
7562                el_act2img(effective_element, action) :
7563                el_act_dir2img(effective_element, action, direction));
7564
7565     g = &graphic_info[graphic];
7566   }
7567
7568 #if 0
7569   if (tile == Xsand_stonesand_1 ||
7570       tile == Xsand_stonesand_2 ||
7571       tile == Xsand_stonesand_3 ||
7572       tile == Xsand_stonesand_4)
7573     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7574 #endif
7575
7576 #if 1
7577   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
7578   {
7579     GfxFrame[x][y] = 0;
7580
7581     // printf("::: resetting... [%d]\n", tile);
7582   }
7583 #else
7584   if (action_removing || check_linear_animation_EM(tile))
7585   {
7586     GfxFrame[x][y] = frame_em;
7587
7588     // printf("::: resetting... [%d]\n", tile);
7589   }
7590 #endif
7591   else if (action_moving)
7592   {
7593     boolean is_backside = object_mapping[tile].is_backside;
7594
7595     if (is_backside)
7596     {
7597       int direction = object_mapping[tile].direction;
7598       int move_dir = (action_falling ? MV_DOWN : direction);
7599
7600       GfxFrame[x][y]++;
7601
7602 #if 1
7603       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7604       if (g->double_movement && frame_em == 0)
7605       {
7606         GfxFrame[x][y] = 0;
7607
7608         // printf("::: resetting... [%d]\n", tile);
7609       }
7610 #endif
7611
7612       if (move_dir == MV_LEFT)
7613         GfxFrame[x - 1][y] = GfxFrame[x][y];
7614       else if (move_dir == MV_RIGHT)
7615         GfxFrame[x + 1][y] = GfxFrame[x][y];
7616       else if (move_dir == MV_UP)
7617         GfxFrame[x][y - 1] = GfxFrame[x][y];
7618       else if (move_dir == MV_DOWN)
7619         GfxFrame[x][y + 1] = GfxFrame[x][y];
7620     }
7621   }
7622   else
7623   {
7624     GfxFrame[x][y]++;
7625
7626     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7627     if (tile == Xsand_stonesand_quickout_1 ||
7628         tile == Xsand_stonesand_quickout_2)
7629       GfxFrame[x][y]++;
7630   }
7631
7632 #if 0
7633   if (tile == Xsand_stonesand_1 ||
7634       tile == Xsand_stonesand_2 ||
7635       tile == Xsand_stonesand_3 ||
7636       tile == Xsand_stonesand_4)
7637     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
7638 #endif
7639
7640 #if 1
7641   if (graphic_info[graphic].anim_global_sync)
7642     sync_frame = FrameCounter;
7643   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7644     sync_frame = GfxFrame[x][y];
7645   else
7646     sync_frame = 0;     /* playfield border (pseudo steel) */
7647
7648   SetRandomAnimationValue(x, y);
7649
7650   int frame = getAnimationFrame(g->anim_frames,
7651                                 g->anim_delay,
7652                                 g->anim_mode,
7653                                 g->anim_start_frame,
7654                                 sync_frame);
7655
7656   g_em->unique_identifier =
7657     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7658 #endif
7659 }
7660
7661 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7662                                   int tile, int frame_em, int x, int y)
7663 {
7664   int action = object_mapping[tile].action;
7665   int direction = object_mapping[tile].direction;
7666   boolean is_backside = object_mapping[tile].is_backside;
7667   int effective_element = get_effective_element_EM(tile, frame_em);
7668 #if 1
7669   int effective_action = action;
7670 #else
7671   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
7672 #endif
7673   int graphic = (direction == MV_NONE ?
7674                  el_act2img(effective_element, effective_action) :
7675                  el_act_dir2img(effective_element, effective_action,
7676                                 direction));
7677   int crumbled = (direction == MV_NONE ?
7678                   el_act2crm(effective_element, effective_action) :
7679                   el_act_dir2crm(effective_element, effective_action,
7680                                  direction));
7681   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7682   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7683   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7684   struct GraphicInfo *g = &graphic_info[graphic];
7685 #if 0
7686   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7687 #endif
7688   int sync_frame;
7689
7690   /* special case: graphic uses "2nd movement tile" and has defined
7691      7 frames for movement animation (or less) => use default graphic
7692      for last (8th) frame which ends the movement animation */
7693   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7694   {
7695     effective_action = ACTION_DEFAULT;
7696     graphic = (direction == MV_NONE ?
7697                el_act2img(effective_element, effective_action) :
7698                el_act_dir2img(effective_element, effective_action,
7699                               direction));
7700     crumbled = (direction == MV_NONE ?
7701                 el_act2crm(effective_element, effective_action) :
7702                 el_act_dir2crm(effective_element, effective_action,
7703                                direction));
7704
7705     g = &graphic_info[graphic];
7706   }
7707
7708 #if 0
7709   if (frame_em == 7)
7710     return;
7711 #endif
7712
7713
7714 #if 0
7715   if (frame_em == 0)    /* reset animation frame for certain elements */
7716   {
7717     if (check_linear_animation_EM(tile))
7718       GfxFrame[x][y] = 0;
7719   }
7720 #endif
7721
7722   if (graphic_info[graphic].anim_global_sync)
7723     sync_frame = FrameCounter;
7724   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7725     sync_frame = GfxFrame[x][y];
7726   else
7727     sync_frame = 0;     /* playfield border (pseudo steel) */
7728
7729   SetRandomAnimationValue(x, y);
7730
7731 #if 0
7732   int i = tile;
7733   int j = frame_em;
7734   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7735                         i == Xdrip_stretchB ? 7 :
7736                         i == Ydrip_s2 ? j + 8 :
7737                         i == Ydrip_s2B ? j + 8 :
7738                         i == Xacid_1 ? 0 :
7739                         i == Xacid_2 ? 10 :
7740                         i == Xacid_3 ? 20 :
7741                         i == Xacid_4 ? 30 :
7742                         i == Xacid_5 ? 40 :
7743                         i == Xacid_6 ? 50 :
7744                         i == Xacid_7 ? 60 :
7745                         i == Xacid_8 ? 70 :
7746                         i == Xfake_acid_1 ? 0 :
7747                         i == Xfake_acid_2 ? 10 :
7748                         i == Xfake_acid_3 ? 20 :
7749                         i == Xfake_acid_4 ? 30 :
7750                         i == Xfake_acid_5 ? 40 :
7751                         i == Xfake_acid_6 ? 50 :
7752                         i == Xfake_acid_7 ? 60 :
7753                         i == Xfake_acid_8 ? 70 :
7754                         i == Xball_2 ? 7 :
7755                         i == Xball_2B ? j + 8 :
7756                         i == Yball_eat ? j + 1 :
7757                         i == Ykey_1_eat ? j + 1 :
7758                         i == Ykey_2_eat ? j + 1 :
7759                         i == Ykey_3_eat ? j + 1 :
7760                         i == Ykey_4_eat ? j + 1 :
7761                         i == Ykey_5_eat ? j + 1 :
7762                         i == Ykey_6_eat ? j + 1 :
7763                         i == Ykey_7_eat ? j + 1 :
7764                         i == Ykey_8_eat ? j + 1 :
7765                         i == Ylenses_eat ? j + 1 :
7766                         i == Ymagnify_eat ? j + 1 :
7767                         i == Ygrass_eat ? j + 1 :
7768                         i == Ydirt_eat ? j + 1 :
7769                         i == Xamoeba_1 ? 0 :
7770                         i == Xamoeba_2 ? 1 :
7771                         i == Xamoeba_3 ? 2 :
7772                         i == Xamoeba_4 ? 3 :
7773                         i == Xamoeba_5 ? 0 :
7774                         i == Xamoeba_6 ? 1 :
7775                         i == Xamoeba_7 ? 2 :
7776                         i == Xamoeba_8 ? 3 :
7777                         i == Xexit_2 ? j + 8 :
7778                         i == Xexit_3 ? j + 16 :
7779                         i == Xdynamite_1 ? 0 :
7780                         i == Xdynamite_2 ? 8 :
7781                         i == Xdynamite_3 ? 16 :
7782                         i == Xdynamite_4 ? 24 :
7783                         i == Xsand_stonein_1 ? j + 1 :
7784                         i == Xsand_stonein_2 ? j + 9 :
7785                         i == Xsand_stonein_3 ? j + 17 :
7786                         i == Xsand_stonein_4 ? j + 25 :
7787                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7788                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7789                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7790                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7791                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7792                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7793                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7794                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7795                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7796                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7797                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7798                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7799                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7800                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7801                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7802                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7803                         i == Xboom_bug && j == 1 ? 2 :
7804                         i == Xboom_bug && j == 2 ? 2 :
7805                         i == Xboom_bug && j == 3 ? 4 :
7806                         i == Xboom_bug && j == 4 ? 4 :
7807                         i == Xboom_bug && j == 5 ? 2 :
7808                         i == Xboom_bug && j == 6 ? 2 :
7809                         i == Xboom_bug && j == 7 ? 0 :
7810                         i == Xboom_bomb && j == 1 ? 2 :
7811                         i == Xboom_bomb && j == 2 ? 2 :
7812                         i == Xboom_bomb && j == 3 ? 4 :
7813                         i == Xboom_bomb && j == 4 ? 4 :
7814                         i == Xboom_bomb && j == 5 ? 2 :
7815                         i == Xboom_bomb && j == 6 ? 2 :
7816                         i == Xboom_bomb && j == 7 ? 0 :
7817                         i == Xboom_android && j == 7 ? 6 :
7818                         i == Xboom_1 && j == 1 ? 2 :
7819                         i == Xboom_1 && j == 2 ? 2 :
7820                         i == Xboom_1 && j == 3 ? 4 :
7821                         i == Xboom_1 && j == 4 ? 4 :
7822                         i == Xboom_1 && j == 5 ? 6 :
7823                         i == Xboom_1 && j == 6 ? 6 :
7824                         i == Xboom_1 && j == 7 ? 8 :
7825                         i == Xboom_2 && j == 0 ? 8 :
7826                         i == Xboom_2 && j == 1 ? 8 :
7827                         i == Xboom_2 && j == 2 ? 10 :
7828                         i == Xboom_2 && j == 3 ? 10 :
7829                         i == Xboom_2 && j == 4 ? 10 :
7830                         i == Xboom_2 && j == 5 ? 12 :
7831                         i == Xboom_2 && j == 6 ? 12 :
7832                         i == Xboom_2 && j == 7 ? 12 :
7833 #if 0
7834                         special_animation && j == 4 ? 3 :
7835                         effective_action != action ? 0 :
7836 #endif
7837                         j);
7838 #endif
7839
7840 #if 0
7841   int xxx_effective_action;
7842   int xxx_has_action_graphics;
7843
7844   {
7845     int element = object_mapping[i].element_rnd;
7846     int action = object_mapping[i].action;
7847     int direction = object_mapping[i].direction;
7848     boolean is_backside = object_mapping[i].is_backside;
7849 #if 0
7850     boolean action_removing = (action == ACTION_DIGGING ||
7851                                action == ACTION_SNAPPING ||
7852                                action == ACTION_COLLECTING);
7853 #endif
7854     boolean action_exploding = ((action == ACTION_EXPLODING ||
7855                                  action == ACTION_SMASHED_BY_ROCK ||
7856                                  action == ACTION_SMASHED_BY_SPRING) &&
7857                                 element != EL_DIAMOND);
7858     boolean action_active = (action == ACTION_ACTIVE);
7859     boolean action_other = (action == ACTION_OTHER);
7860
7861     {
7862 #if 1
7863       int effective_element = get_effective_element_EM(i, j);
7864 #else
7865       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
7866                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
7867                                j < 7 ? element :
7868                                i == Xdrip_stretch ? element :
7869                                i == Xdrip_stretchB ? element :
7870                                i == Ydrip_s1 ? element :
7871                                i == Ydrip_s1B ? element :
7872                                i == Xball_1B ? element :
7873                                i == Xball_2 ? element :
7874                                i == Xball_2B ? element :
7875                                i == Yball_eat ? element :
7876                                i == Ykey_1_eat ? element :
7877                                i == Ykey_2_eat ? element :
7878                                i == Ykey_3_eat ? element :
7879                                i == Ykey_4_eat ? element :
7880                                i == Ykey_5_eat ? element :
7881                                i == Ykey_6_eat ? element :
7882                                i == Ykey_7_eat ? element :
7883                                i == Ykey_8_eat ? element :
7884                                i == Ylenses_eat ? element :
7885                                i == Ymagnify_eat ? element :
7886                                i == Ygrass_eat ? element :
7887                                i == Ydirt_eat ? element :
7888                                i == Yemerald_stone ? EL_EMERALD :
7889                                i == Ydiamond_stone ? EL_ROCK :
7890                                i == Xsand_stonein_1 ? element :
7891                                i == Xsand_stonein_2 ? element :
7892                                i == Xsand_stonein_3 ? element :
7893                                i == Xsand_stonein_4 ? element :
7894                                is_backside ? EL_EMPTY :
7895                                action_removing ? EL_EMPTY :
7896                                element);
7897 #endif
7898       int effective_action = (j < 7 ? action :
7899                               i == Xdrip_stretch ? action :
7900                               i == Xdrip_stretchB ? action :
7901                               i == Ydrip_s1 ? action :
7902                               i == Ydrip_s1B ? action :
7903                               i == Xball_1B ? action :
7904                               i == Xball_2 ? action :
7905                               i == Xball_2B ? action :
7906                               i == Yball_eat ? action :
7907                               i == Ykey_1_eat ? action :
7908                               i == Ykey_2_eat ? action :
7909                               i == Ykey_3_eat ? action :
7910                               i == Ykey_4_eat ? action :
7911                               i == Ykey_5_eat ? action :
7912                               i == Ykey_6_eat ? action :
7913                               i == Ykey_7_eat ? action :
7914                               i == Ykey_8_eat ? action :
7915                               i == Ylenses_eat ? action :
7916                               i == Ymagnify_eat ? action :
7917                               i == Ygrass_eat ? action :
7918                               i == Ydirt_eat ? action :
7919                               i == Xsand_stonein_1 ? action :
7920                               i == Xsand_stonein_2 ? action :
7921                               i == Xsand_stonein_3 ? action :
7922                               i == Xsand_stonein_4 ? action :
7923                               i == Xsand_stoneout_1 ? action :
7924                               i == Xsand_stoneout_2 ? action :
7925                               i == Xboom_android ? ACTION_EXPLODING :
7926                               action_exploding ? ACTION_EXPLODING :
7927                               action_active ? action :
7928                               action_other ? action :
7929                               ACTION_DEFAULT);
7930       int graphic = (el_act_dir2img(effective_element, effective_action,
7931                                     direction));
7932       int crumbled = (el_act_dir2crm(effective_element, effective_action,
7933                                      direction));
7934       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7935       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7936       boolean has_action_graphics = (graphic != base_graphic);
7937       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7938       struct GraphicInfo *g = &graphic_info[graphic];
7939 #if 0
7940       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
7941 #endif
7942       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7943       Bitmap *src_bitmap;
7944       int src_x, src_y;
7945       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7946       boolean special_animation = (action != ACTION_DEFAULT &&
7947                                    g->anim_frames == 3 &&
7948                                    g->anim_delay == 2 &&
7949                                    g->anim_mode & ANIM_LINEAR);
7950       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
7951                         i == Xdrip_stretchB ? 7 :
7952                         i == Ydrip_s2 ? j + 8 :
7953                         i == Ydrip_s2B ? j + 8 :
7954                         i == Xacid_1 ? 0 :
7955                         i == Xacid_2 ? 10 :
7956                         i == Xacid_3 ? 20 :
7957                         i == Xacid_4 ? 30 :
7958                         i == Xacid_5 ? 40 :
7959                         i == Xacid_6 ? 50 :
7960                         i == Xacid_7 ? 60 :
7961                         i == Xacid_8 ? 70 :
7962                         i == Xfake_acid_1 ? 0 :
7963                         i == Xfake_acid_2 ? 10 :
7964                         i == Xfake_acid_3 ? 20 :
7965                         i == Xfake_acid_4 ? 30 :
7966                         i == Xfake_acid_5 ? 40 :
7967                         i == Xfake_acid_6 ? 50 :
7968                         i == Xfake_acid_7 ? 60 :
7969                         i == Xfake_acid_8 ? 70 :
7970                         i == Xball_2 ? 7 :
7971                         i == Xball_2B ? j + 8 :
7972                         i == Yball_eat ? j + 1 :
7973                         i == Ykey_1_eat ? j + 1 :
7974                         i == Ykey_2_eat ? j + 1 :
7975                         i == Ykey_3_eat ? j + 1 :
7976                         i == Ykey_4_eat ? j + 1 :
7977                         i == Ykey_5_eat ? j + 1 :
7978                         i == Ykey_6_eat ? j + 1 :
7979                         i == Ykey_7_eat ? j + 1 :
7980                         i == Ykey_8_eat ? j + 1 :
7981                         i == Ylenses_eat ? j + 1 :
7982                         i == Ymagnify_eat ? j + 1 :
7983                         i == Ygrass_eat ? j + 1 :
7984                         i == Ydirt_eat ? j + 1 :
7985                         i == Xamoeba_1 ? 0 :
7986                         i == Xamoeba_2 ? 1 :
7987                         i == Xamoeba_3 ? 2 :
7988                         i == Xamoeba_4 ? 3 :
7989                         i == Xamoeba_5 ? 0 :
7990                         i == Xamoeba_6 ? 1 :
7991                         i == Xamoeba_7 ? 2 :
7992                         i == Xamoeba_8 ? 3 :
7993                         i == Xexit_2 ? j + 8 :
7994                         i == Xexit_3 ? j + 16 :
7995                         i == Xdynamite_1 ? 0 :
7996                         i == Xdynamite_2 ? 8 :
7997                         i == Xdynamite_3 ? 16 :
7998                         i == Xdynamite_4 ? 24 :
7999                         i == Xsand_stonein_1 ? j + 1 :
8000                         i == Xsand_stonein_2 ? j + 9 :
8001                         i == Xsand_stonein_3 ? j + 17 :
8002                         i == Xsand_stonein_4 ? j + 25 :
8003                         i == Xsand_stoneout_1 && j == 0 ? 0 :
8004                         i == Xsand_stoneout_1 && j == 1 ? 0 :
8005                         i == Xsand_stoneout_1 && j == 2 ? 1 :
8006                         i == Xsand_stoneout_1 && j == 3 ? 2 :
8007                         i == Xsand_stoneout_1 && j == 4 ? 2 :
8008                         i == Xsand_stoneout_1 && j == 5 ? 3 :
8009                         i == Xsand_stoneout_1 && j == 6 ? 4 :
8010                         i == Xsand_stoneout_1 && j == 7 ? 4 :
8011                         i == Xsand_stoneout_2 && j == 0 ? 5 :
8012                         i == Xsand_stoneout_2 && j == 1 ? 6 :
8013                         i == Xsand_stoneout_2 && j == 2 ? 7 :
8014                         i == Xsand_stoneout_2 && j == 3 ? 8 :
8015                         i == Xsand_stoneout_2 && j == 4 ? 9 :
8016                         i == Xsand_stoneout_2 && j == 5 ? 11 :
8017                         i == Xsand_stoneout_2 && j == 6 ? 13 :
8018                         i == Xsand_stoneout_2 && j == 7 ? 15 :
8019                         i == Xboom_bug && j == 1 ? 2 :
8020                         i == Xboom_bug && j == 2 ? 2 :
8021                         i == Xboom_bug && j == 3 ? 4 :
8022                         i == Xboom_bug && j == 4 ? 4 :
8023                         i == Xboom_bug && j == 5 ? 2 :
8024                         i == Xboom_bug && j == 6 ? 2 :
8025                         i == Xboom_bug && j == 7 ? 0 :
8026                         i == Xboom_bomb && j == 1 ? 2 :
8027                         i == Xboom_bomb && j == 2 ? 2 :
8028                         i == Xboom_bomb && j == 3 ? 4 :
8029                         i == Xboom_bomb && j == 4 ? 4 :
8030                         i == Xboom_bomb && j == 5 ? 2 :
8031                         i == Xboom_bomb && j == 6 ? 2 :
8032                         i == Xboom_bomb && j == 7 ? 0 :
8033                         i == Xboom_android && j == 7 ? 6 :
8034                         i == Xboom_1 && j == 1 ? 2 :
8035                         i == Xboom_1 && j == 2 ? 2 :
8036                         i == Xboom_1 && j == 3 ? 4 :
8037                         i == Xboom_1 && j == 4 ? 4 :
8038                         i == Xboom_1 && j == 5 ? 6 :
8039                         i == Xboom_1 && j == 6 ? 6 :
8040                         i == Xboom_1 && j == 7 ? 8 :
8041                         i == Xboom_2 && j == 0 ? 8 :
8042                         i == Xboom_2 && j == 1 ? 8 :
8043                         i == Xboom_2 && j == 2 ? 10 :
8044                         i == Xboom_2 && j == 3 ? 10 :
8045                         i == Xboom_2 && j == 4 ? 10 :
8046                         i == Xboom_2 && j == 5 ? 12 :
8047                         i == Xboom_2 && j == 6 ? 12 :
8048                         i == Xboom_2 && j == 7 ? 12 :
8049                         special_animation && j == 4 ? 3 :
8050                         effective_action != action ? 0 :
8051                         j);
8052
8053       xxx_effective_action = effective_action;
8054       xxx_has_action_graphics = has_action_graphics;
8055     }
8056   }
8057 #endif
8058
8059   int frame = getAnimationFrame(g->anim_frames,
8060                                 g->anim_delay,
8061                                 g->anim_mode,
8062                                 g->anim_start_frame,
8063                                 sync_frame);
8064
8065
8066 #if 0
8067   return;
8068 #endif
8069
8070 #if 0
8071   if (frame_em == 7)
8072     return;
8073 #endif
8074
8075 #if 0
8076   int old_src_x = g_em->src_x;
8077   int old_src_y = g_em->src_y;
8078 #endif
8079
8080 #if 1
8081   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8082                       g->double_movement && is_backside);
8083 #else
8084   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8085                       &g_em->src_x, &g_em->src_y, FALSE);
8086 #endif
8087
8088
8089 #if 0
8090   if (tile == Ydiamond_stone)
8091     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
8092            frame_em,
8093            g->anim_frames,
8094            g->anim_delay,
8095            g->anim_mode,
8096            g->anim_start_frame,
8097            sync_frame,
8098            frame,
8099            g_em->src_x, g_em->src_y,
8100            g_em->src_offset_x, g_em->src_offset_y,
8101            g_em->dst_offset_x, g_em->dst_offset_y,
8102            graphic);
8103 #endif
8104
8105
8106 #if 0
8107   return;
8108 #endif
8109
8110 #if 0
8111   if (frame_em == 7)
8112   {
8113     if (graphic == IMG_BUG_MOVING_RIGHT)
8114       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8115              g->double_movement, is_backside,
8116              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8117
8118     return;
8119   }
8120 #endif
8121
8122
8123 #if 0
8124   g_em->src_offset_x = 0;
8125   g_em->src_offset_y = 0;
8126   g_em->dst_offset_x = 0;
8127   g_em->dst_offset_y = 0;
8128   g_em->width  = TILEX;
8129   g_em->height = TILEY;
8130
8131   g_em->preserve_background = FALSE;
8132 #endif
8133
8134   /* (updating the "crumbled" graphic definitions is probably not really needed,
8135      as animations for crumbled graphics can't be longer than one EMC cycle) */
8136 #if 1
8137   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8138                            sync_frame);
8139
8140 #else
8141
8142   g_em->crumbled_bitmap = NULL;
8143   g_em->crumbled_src_x = 0;
8144   g_em->crumbled_src_y = 0;
8145
8146   g_em->has_crumbled_graphics = FALSE;
8147
8148   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8149   {
8150     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8151                                            g_crumbled->anim_delay,
8152                                            g_crumbled->anim_mode,
8153                                            g_crumbled->anim_start_frame,
8154                                            sync_frame);
8155
8156     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8157                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8158
8159     g_em->has_crumbled_graphics = TRUE;
8160   }
8161 #endif
8162
8163 #if 0
8164  {
8165    int effective_action = xxx_effective_action;
8166    int has_action_graphics = xxx_has_action_graphics;
8167
8168       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8169                                    effective_action == ACTION_MOVING  ||
8170                                    effective_action == ACTION_PUSHING ||
8171                                    effective_action == ACTION_EATING)) ||
8172           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8173                                     effective_action == ACTION_EMPTYING)))
8174       {
8175         int move_dir =
8176           (effective_action == ACTION_FALLING ||
8177            effective_action == ACTION_FILLING ||
8178            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8179         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8180         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8181         int num_steps = (i == Ydrip_s1  ? 16 :
8182                          i == Ydrip_s1B ? 16 :
8183                          i == Ydrip_s2  ? 16 :
8184                          i == Ydrip_s2B ? 16 :
8185                          i == Xsand_stonein_1 ? 32 :
8186                          i == Xsand_stonein_2 ? 32 :
8187                          i == Xsand_stonein_3 ? 32 :
8188                          i == Xsand_stonein_4 ? 32 :
8189                          i == Xsand_stoneout_1 ? 16 :
8190                          i == Xsand_stoneout_2 ? 16 : 8);
8191         int cx = ABS(dx) * (TILEX / num_steps);
8192         int cy = ABS(dy) * (TILEY / num_steps);
8193         int step_frame = (i == Ydrip_s2         ? j + 8 :
8194                           i == Ydrip_s2B        ? j + 8 :
8195                           i == Xsand_stonein_2  ? j + 8 :
8196                           i == Xsand_stonein_3  ? j + 16 :
8197                           i == Xsand_stonein_4  ? j + 24 :
8198                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8199         int step = (is_backside ? step_frame : num_steps - step_frame);
8200
8201         if (is_backside)        /* tile where movement starts */
8202         {
8203           if (dx < 0 || dy < 0)
8204           {
8205             g_em->src_offset_x = cx * step;
8206             g_em->src_offset_y = cy * step;
8207           }
8208           else
8209           {
8210             g_em->dst_offset_x = cx * step;
8211             g_em->dst_offset_y = cy * step;
8212           }
8213         }
8214         else                    /* tile where movement ends */
8215         {
8216           if (dx < 0 || dy < 0)
8217           {
8218             g_em->dst_offset_x = cx * step;
8219             g_em->dst_offset_y = cy * step;
8220           }
8221           else
8222           {
8223             g_em->src_offset_x = cx * step;
8224             g_em->src_offset_y = cy * step;
8225           }
8226         }
8227
8228         g_em->width  = TILEX - cx * step;
8229         g_em->height = TILEY - cy * step;
8230       }
8231
8232       /* create unique graphic identifier to decide if tile must be redrawn */
8233       /* bit 31 - 16 (16 bit): EM style graphic
8234          bit 15 - 12 ( 4 bit): EM style frame
8235          bit 11 -  6 ( 6 bit): graphic width
8236          bit  5 -  0 ( 6 bit): graphic height */
8237       g_em->unique_identifier =
8238         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8239  }
8240 #endif
8241
8242 }
8243
8244 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
8245                                   int player_nr, int anim, int frame_em)
8246 {
8247   int element   = player_mapping[player_nr][anim].element_rnd;
8248   int action    = player_mapping[player_nr][anim].action;
8249   int direction = player_mapping[player_nr][anim].direction;
8250   int graphic = (direction == MV_NONE ?
8251                  el_act2img(element, action) :
8252                  el_act_dir2img(element, action, direction));
8253   struct GraphicInfo *g = &graphic_info[graphic];
8254   int sync_frame;
8255
8256   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
8257
8258   stored_player[player_nr].StepFrame = frame_em;
8259
8260   sync_frame = stored_player[player_nr].Frame;
8261
8262   int frame = getAnimationFrame(g->anim_frames,
8263                                 g->anim_delay,
8264                                 g->anim_mode,
8265                                 g->anim_start_frame,
8266                                 sync_frame);
8267
8268   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8269                       &g_em->src_x, &g_em->src_y, FALSE);
8270
8271 #if 0
8272   printf("::: %d: %d, %d [%d]\n",
8273          player_nr,
8274          stored_player[player_nr].Frame,
8275          stored_player[player_nr].StepFrame,
8276          FrameCounter);
8277 #endif
8278 }
8279
8280 void InitGraphicInfo_EM(void)
8281 {
8282 #if 0
8283   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8284   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8285 #endif
8286   int i, j, p;
8287
8288 #if DEBUG_EM_GFX
8289   int num_em_gfx_errors = 0;
8290
8291   if (graphic_info_em_object[0][0].bitmap == NULL)
8292   {
8293     /* EM graphics not yet initialized in em_open_all() */
8294
8295     return;
8296   }
8297
8298   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
8299 #endif
8300
8301   /* always start with reliable default values */
8302   for (i = 0; i < TILE_MAX; i++)
8303   {
8304     object_mapping[i].element_rnd = EL_UNKNOWN;
8305     object_mapping[i].is_backside = FALSE;
8306     object_mapping[i].action = ACTION_DEFAULT;
8307     object_mapping[i].direction = MV_NONE;
8308   }
8309
8310   /* always start with reliable default values */
8311   for (p = 0; p < MAX_PLAYERS; p++)
8312   {
8313     for (i = 0; i < SPR_MAX; i++)
8314     {
8315       player_mapping[p][i].element_rnd = EL_UNKNOWN;
8316       player_mapping[p][i].action = ACTION_DEFAULT;
8317       player_mapping[p][i].direction = MV_NONE;
8318     }
8319   }
8320
8321   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
8322   {
8323     int e = em_object_mapping_list[i].element_em;
8324
8325     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
8326     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
8327
8328     if (em_object_mapping_list[i].action != -1)
8329       object_mapping[e].action = em_object_mapping_list[i].action;
8330
8331     if (em_object_mapping_list[i].direction != -1)
8332       object_mapping[e].direction =
8333         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
8334   }
8335
8336   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
8337   {
8338     int a = em_player_mapping_list[i].action_em;
8339     int p = em_player_mapping_list[i].player_nr;
8340
8341     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
8342
8343     if (em_player_mapping_list[i].action != -1)
8344       player_mapping[p][a].action = em_player_mapping_list[i].action;
8345
8346     if (em_player_mapping_list[i].direction != -1)
8347       player_mapping[p][a].direction =
8348         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
8349   }
8350
8351   for (i = 0; i < TILE_MAX; i++)
8352   {
8353     int element = object_mapping[i].element_rnd;
8354     int action = object_mapping[i].action;
8355     int direction = object_mapping[i].direction;
8356     boolean is_backside = object_mapping[i].is_backside;
8357 #if 0
8358     boolean action_removing = (action == ACTION_DIGGING ||
8359                                action == ACTION_SNAPPING ||
8360                                action == ACTION_COLLECTING);
8361 #endif
8362     boolean action_exploding = ((action == ACTION_EXPLODING ||
8363                                  action == ACTION_SMASHED_BY_ROCK ||
8364                                  action == ACTION_SMASHED_BY_SPRING) &&
8365                                 element != EL_DIAMOND);
8366     boolean action_active = (action == ACTION_ACTIVE);
8367     boolean action_other = (action == ACTION_OTHER);
8368
8369     for (j = 0; j < 8; j++)
8370     {
8371 #if 1
8372       int effective_element = get_effective_element_EM(i, j);
8373 #else
8374       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8375                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8376                                j < 7 ? element :
8377                                i == Xdrip_stretch ? element :
8378                                i == Xdrip_stretchB ? element :
8379                                i == Ydrip_s1 ? element :
8380                                i == Ydrip_s1B ? element :
8381                                i == Xball_1B ? element :
8382                                i == Xball_2 ? element :
8383                                i == Xball_2B ? element :
8384                                i == Yball_eat ? element :
8385                                i == Ykey_1_eat ? element :
8386                                i == Ykey_2_eat ? element :
8387                                i == Ykey_3_eat ? element :
8388                                i == Ykey_4_eat ? element :
8389                                i == Ykey_5_eat ? element :
8390                                i == Ykey_6_eat ? element :
8391                                i == Ykey_7_eat ? element :
8392                                i == Ykey_8_eat ? element :
8393                                i == Ylenses_eat ? element :
8394                                i == Ymagnify_eat ? element :
8395                                i == Ygrass_eat ? element :
8396                                i == Ydirt_eat ? element :
8397                                i == Yemerald_stone ? EL_EMERALD :
8398                                i == Ydiamond_stone ? EL_ROCK :
8399                                i == Xsand_stonein_1 ? element :
8400                                i == Xsand_stonein_2 ? element :
8401                                i == Xsand_stonein_3 ? element :
8402                                i == Xsand_stonein_4 ? element :
8403                                is_backside ? EL_EMPTY :
8404                                action_removing ? EL_EMPTY :
8405                                element);
8406 #endif
8407       int effective_action = (j < 7 ? action :
8408                               i == Xdrip_stretch ? action :
8409                               i == Xdrip_stretchB ? action :
8410                               i == Ydrip_s1 ? action :
8411                               i == Ydrip_s1B ? action :
8412                               i == Xball_1B ? action :
8413                               i == Xball_2 ? action :
8414                               i == Xball_2B ? action :
8415                               i == Yball_eat ? action :
8416                               i == Ykey_1_eat ? action :
8417                               i == Ykey_2_eat ? action :
8418                               i == Ykey_3_eat ? action :
8419                               i == Ykey_4_eat ? action :
8420                               i == Ykey_5_eat ? action :
8421                               i == Ykey_6_eat ? action :
8422                               i == Ykey_7_eat ? action :
8423                               i == Ykey_8_eat ? action :
8424                               i == Ylenses_eat ? action :
8425                               i == Ymagnify_eat ? action :
8426                               i == Ygrass_eat ? action :
8427                               i == Ydirt_eat ? action :
8428                               i == Xsand_stonein_1 ? action :
8429                               i == Xsand_stonein_2 ? action :
8430                               i == Xsand_stonein_3 ? action :
8431                               i == Xsand_stonein_4 ? action :
8432                               i == Xsand_stoneout_1 ? action :
8433                               i == Xsand_stoneout_2 ? action :
8434                               i == Xboom_android ? ACTION_EXPLODING :
8435                               action_exploding ? ACTION_EXPLODING :
8436                               action_active ? action :
8437                               action_other ? action :
8438                               ACTION_DEFAULT);
8439       int graphic = (el_act_dir2img(effective_element, effective_action,
8440                                     direction));
8441       int crumbled = (el_act_dir2crm(effective_element, effective_action,
8442                                      direction));
8443       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8444       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8445       boolean has_action_graphics = (graphic != base_graphic);
8446       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8447       struct GraphicInfo *g = &graphic_info[graphic];
8448 #if 0
8449       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8450 #endif
8451       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8452       Bitmap *src_bitmap;
8453       int src_x, src_y;
8454       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8455       boolean special_animation = (action != ACTION_DEFAULT &&
8456                                    g->anim_frames == 3 &&
8457                                    g->anim_delay == 2 &&
8458                                    g->anim_mode & ANIM_LINEAR);
8459       int sync_frame = (i == Xdrip_stretch ? 7 :
8460                         i == Xdrip_stretchB ? 7 :
8461                         i == Ydrip_s2 ? j + 8 :
8462                         i == Ydrip_s2B ? j + 8 :
8463                         i == Xacid_1 ? 0 :
8464                         i == Xacid_2 ? 10 :
8465                         i == Xacid_3 ? 20 :
8466                         i == Xacid_4 ? 30 :
8467                         i == Xacid_5 ? 40 :
8468                         i == Xacid_6 ? 50 :
8469                         i == Xacid_7 ? 60 :
8470                         i == Xacid_8 ? 70 :
8471                         i == Xfake_acid_1 ? 0 :
8472                         i == Xfake_acid_2 ? 10 :
8473                         i == Xfake_acid_3 ? 20 :
8474                         i == Xfake_acid_4 ? 30 :
8475                         i == Xfake_acid_5 ? 40 :
8476                         i == Xfake_acid_6 ? 50 :
8477                         i == Xfake_acid_7 ? 60 :
8478                         i == Xfake_acid_8 ? 70 :
8479                         i == Xball_2 ? 7 :
8480                         i == Xball_2B ? j + 8 :
8481                         i == Yball_eat ? j + 1 :
8482                         i == Ykey_1_eat ? j + 1 :
8483                         i == Ykey_2_eat ? j + 1 :
8484                         i == Ykey_3_eat ? j + 1 :
8485                         i == Ykey_4_eat ? j + 1 :
8486                         i == Ykey_5_eat ? j + 1 :
8487                         i == Ykey_6_eat ? j + 1 :
8488                         i == Ykey_7_eat ? j + 1 :
8489                         i == Ykey_8_eat ? j + 1 :
8490                         i == Ylenses_eat ? j + 1 :
8491                         i == Ymagnify_eat ? j + 1 :
8492                         i == Ygrass_eat ? j + 1 :
8493                         i == Ydirt_eat ? j + 1 :
8494                         i == Xamoeba_1 ? 0 :
8495                         i == Xamoeba_2 ? 1 :
8496                         i == Xamoeba_3 ? 2 :
8497                         i == Xamoeba_4 ? 3 :
8498                         i == Xamoeba_5 ? 0 :
8499                         i == Xamoeba_6 ? 1 :
8500                         i == Xamoeba_7 ? 2 :
8501                         i == Xamoeba_8 ? 3 :
8502                         i == Xexit_2 ? j + 8 :
8503                         i == Xexit_3 ? j + 16 :
8504                         i == Xdynamite_1 ? 0 :
8505                         i == Xdynamite_2 ? 8 :
8506                         i == Xdynamite_3 ? 16 :
8507                         i == Xdynamite_4 ? 24 :
8508                         i == Xsand_stonein_1 ? j + 1 :
8509                         i == Xsand_stonein_2 ? j + 9 :
8510                         i == Xsand_stonein_3 ? j + 17 :
8511                         i == Xsand_stonein_4 ? j + 25 :
8512                         i == Xsand_stoneout_1 && j == 0 ? 0 :
8513                         i == Xsand_stoneout_1 && j == 1 ? 0 :
8514                         i == Xsand_stoneout_1 && j == 2 ? 1 :
8515                         i == Xsand_stoneout_1 && j == 3 ? 2 :
8516                         i == Xsand_stoneout_1 && j == 4 ? 2 :
8517                         i == Xsand_stoneout_1 && j == 5 ? 3 :
8518                         i == Xsand_stoneout_1 && j == 6 ? 4 :
8519                         i == Xsand_stoneout_1 && j == 7 ? 4 :
8520                         i == Xsand_stoneout_2 && j == 0 ? 5 :
8521                         i == Xsand_stoneout_2 && j == 1 ? 6 :
8522                         i == Xsand_stoneout_2 && j == 2 ? 7 :
8523                         i == Xsand_stoneout_2 && j == 3 ? 8 :
8524                         i == Xsand_stoneout_2 && j == 4 ? 9 :
8525                         i == Xsand_stoneout_2 && j == 5 ? 11 :
8526                         i == Xsand_stoneout_2 && j == 6 ? 13 :
8527                         i == Xsand_stoneout_2 && j == 7 ? 15 :
8528                         i == Xboom_bug && j == 1 ? 2 :
8529                         i == Xboom_bug && j == 2 ? 2 :
8530                         i == Xboom_bug && j == 3 ? 4 :
8531                         i == Xboom_bug && j == 4 ? 4 :
8532                         i == Xboom_bug && j == 5 ? 2 :
8533                         i == Xboom_bug && j == 6 ? 2 :
8534                         i == Xboom_bug && j == 7 ? 0 :
8535                         i == Xboom_bomb && j == 1 ? 2 :
8536                         i == Xboom_bomb && j == 2 ? 2 :
8537                         i == Xboom_bomb && j == 3 ? 4 :
8538                         i == Xboom_bomb && j == 4 ? 4 :
8539                         i == Xboom_bomb && j == 5 ? 2 :
8540                         i == Xboom_bomb && j == 6 ? 2 :
8541                         i == Xboom_bomb && j == 7 ? 0 :
8542                         i == Xboom_android && j == 7 ? 6 :
8543                         i == Xboom_1 && j == 1 ? 2 :
8544                         i == Xboom_1 && j == 2 ? 2 :
8545                         i == Xboom_1 && j == 3 ? 4 :
8546                         i == Xboom_1 && j == 4 ? 4 :
8547                         i == Xboom_1 && j == 5 ? 6 :
8548                         i == Xboom_1 && j == 6 ? 6 :
8549                         i == Xboom_1 && j == 7 ? 8 :
8550                         i == Xboom_2 && j == 0 ? 8 :
8551                         i == Xboom_2 && j == 1 ? 8 :
8552                         i == Xboom_2 && j == 2 ? 10 :
8553                         i == Xboom_2 && j == 3 ? 10 :
8554                         i == Xboom_2 && j == 4 ? 10 :
8555                         i == Xboom_2 && j == 5 ? 12 :
8556                         i == Xboom_2 && j == 6 ? 12 :
8557                         i == Xboom_2 && j == 7 ? 12 :
8558                         special_animation && j == 4 ? 3 :
8559                         effective_action != action ? 0 :
8560                         j);
8561
8562 #if DEBUG_EM_GFX
8563       Bitmap *debug_bitmap = g_em->bitmap;
8564       int debug_src_x = g_em->src_x;
8565       int debug_src_y = g_em->src_y;
8566 #endif
8567
8568       int frame = getAnimationFrame(g->anim_frames,
8569                                     g->anim_delay,
8570                                     g->anim_mode,
8571                                     g->anim_start_frame,
8572                                     sync_frame);
8573
8574       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
8575                           g->double_movement && is_backside);
8576
8577       g_em->bitmap = src_bitmap;
8578       g_em->src_x = src_x;
8579       g_em->src_y = src_y;
8580       g_em->src_offset_x = 0;
8581       g_em->src_offset_y = 0;
8582       g_em->dst_offset_x = 0;
8583       g_em->dst_offset_y = 0;
8584       g_em->width  = TILEX;
8585       g_em->height = TILEY;
8586
8587       g_em->preserve_background = FALSE;
8588
8589 #if 1
8590       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8591                                sync_frame);
8592
8593 #else
8594
8595       g_em->crumbled_bitmap = NULL;
8596       g_em->crumbled_src_x = 0;
8597       g_em->crumbled_src_y = 0;
8598       g_em->crumbled_border_size = 0;
8599
8600       g_em->has_crumbled_graphics = FALSE;
8601
8602 #if 0
8603       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
8604         printf("::: empty crumbled: %d [%s], %d, %d\n",
8605                effective_element, element_info[effective_element].token_name,
8606                effective_action, direction);
8607 #endif
8608
8609       /* if element can be crumbled, but certain action graphics are just empty
8610          space (like instantly snapping sand to empty space in 1 frame), do not
8611          treat these empty space graphics as crumbled graphics in EMC engine */
8612       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8613       {
8614         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8615                                                g_crumbled->anim_delay,
8616                                                g_crumbled->anim_mode,
8617                                                g_crumbled->anim_start_frame,
8618                                                sync_frame);
8619
8620         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
8621
8622         g_em->has_crumbled_graphics = TRUE;
8623         g_em->crumbled_bitmap = src_bitmap;
8624         g_em->crumbled_src_x = src_x;
8625         g_em->crumbled_src_y = src_y;
8626         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8627
8628
8629 #if 0
8630         if (g_em == &graphic_info_em_object[207][0])
8631           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
8632                  graphic_info_em_object[207][0].crumbled_src_x,
8633                  graphic_info_em_object[207][0].crumbled_src_y,
8634
8635                  crumbled, frame, src_x, src_y,
8636
8637                  g->anim_frames,
8638                  g->anim_delay,
8639                  g->anim_mode,
8640                  g->anim_start_frame,
8641                  sync_frame,
8642                  gfx.anim_random_frame,
8643                  frame);
8644 #endif
8645
8646 #if 0
8647         printf("::: EMC tile %d is crumbled\n", i);
8648 #endif
8649       }
8650 #endif
8651
8652 #if 0
8653       if (element == EL_ROCK &&
8654           effective_action == ACTION_FILLING)
8655         printf("::: has_action_graphics == %d\n", has_action_graphics);
8656 #endif
8657
8658       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8659                                    effective_action == ACTION_MOVING  ||
8660                                    effective_action == ACTION_PUSHING ||
8661                                    effective_action == ACTION_EATING)) ||
8662           (!has_action_graphics && (effective_action == ACTION_FILLING ||
8663                                     effective_action == ACTION_EMPTYING)))
8664       {
8665         int move_dir =
8666           (effective_action == ACTION_FALLING ||
8667            effective_action == ACTION_FILLING ||
8668            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8669         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
8670         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
8671         int num_steps = (i == Ydrip_s1  ? 16 :
8672                          i == Ydrip_s1B ? 16 :
8673                          i == Ydrip_s2  ? 16 :
8674                          i == Ydrip_s2B ? 16 :
8675                          i == Xsand_stonein_1 ? 32 :
8676                          i == Xsand_stonein_2 ? 32 :
8677                          i == Xsand_stonein_3 ? 32 :
8678                          i == Xsand_stonein_4 ? 32 :
8679                          i == Xsand_stoneout_1 ? 16 :
8680                          i == Xsand_stoneout_2 ? 16 : 8);
8681         int cx = ABS(dx) * (TILEX / num_steps);
8682         int cy = ABS(dy) * (TILEY / num_steps);
8683         int step_frame = (i == Ydrip_s2         ? j + 8 :
8684                           i == Ydrip_s2B        ? j + 8 :
8685                           i == Xsand_stonein_2  ? j + 8 :
8686                           i == Xsand_stonein_3  ? j + 16 :
8687                           i == Xsand_stonein_4  ? j + 24 :
8688                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
8689         int step = (is_backside ? step_frame : num_steps - step_frame);
8690
8691         if (is_backside)        /* tile where movement starts */
8692         {
8693           if (dx < 0 || dy < 0)
8694           {
8695             g_em->src_offset_x = cx * step;
8696             g_em->src_offset_y = cy * step;
8697           }
8698           else
8699           {
8700             g_em->dst_offset_x = cx * step;
8701             g_em->dst_offset_y = cy * step;
8702           }
8703         }
8704         else                    /* tile where movement ends */
8705         {
8706           if (dx < 0 || dy < 0)
8707           {
8708             g_em->dst_offset_x = cx * step;
8709             g_em->dst_offset_y = cy * step;
8710           }
8711           else
8712           {
8713             g_em->src_offset_x = cx * step;
8714             g_em->src_offset_y = cy * step;
8715           }
8716         }
8717
8718         g_em->width  = TILEX - cx * step;
8719         g_em->height = TILEY - cy * step;
8720       }
8721
8722       /* create unique graphic identifier to decide if tile must be redrawn */
8723       /* bit 31 - 16 (16 bit): EM style graphic
8724          bit 15 - 12 ( 4 bit): EM style frame
8725          bit 11 -  6 ( 6 bit): graphic width
8726          bit  5 -  0 ( 6 bit): graphic height */
8727       g_em->unique_identifier =
8728         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
8729
8730 #if DEBUG_EM_GFX
8731
8732       /* skip check for EMC elements not contained in original EMC artwork */
8733       if (element == EL_EMC_FAKE_ACID)
8734         continue;
8735
8736       if (g_em->bitmap != debug_bitmap ||
8737           g_em->src_x != debug_src_x ||
8738           g_em->src_y != debug_src_y ||
8739           g_em->src_offset_x != 0 ||
8740           g_em->src_offset_y != 0 ||
8741           g_em->dst_offset_x != 0 ||
8742           g_em->dst_offset_y != 0 ||
8743           g_em->width != TILEX ||
8744           g_em->height != TILEY)
8745       {
8746         static int last_i = -1;
8747
8748         if (i != last_i)
8749         {
8750           printf("\n");
8751           last_i = i;
8752         }
8753
8754         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
8755                i, element, element_info[element].token_name,
8756                element_action_info[effective_action].suffix, direction);
8757
8758         if (element != effective_element)
8759           printf(" [%d ('%s')]",
8760                  effective_element,
8761                  element_info[effective_element].token_name);
8762
8763         printf("\n");
8764
8765         if (g_em->bitmap != debug_bitmap)
8766           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
8767                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
8768
8769         if (g_em->src_x != debug_src_x ||
8770             g_em->src_y != debug_src_y)
8771           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8772                  j, (is_backside ? 'B' : 'F'),
8773                  g_em->src_x, g_em->src_y,
8774                  g_em->src_x / 32, g_em->src_y / 32,
8775                  debug_src_x, debug_src_y,
8776                  debug_src_x / 32, debug_src_y / 32);
8777
8778         if (g_em->src_offset_x != 0 ||
8779             g_em->src_offset_y != 0 ||
8780             g_em->dst_offset_x != 0 ||
8781             g_em->dst_offset_y != 0)
8782           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
8783                  j, is_backside,
8784                  g_em->src_offset_x, g_em->src_offset_y,
8785                  g_em->dst_offset_x, g_em->dst_offset_y);
8786
8787         if (g_em->width != TILEX ||
8788             g_em->height != TILEY)
8789           printf("    %d (%d): size %d,%d should be %d,%d\n",
8790                  j, is_backside,
8791                  g_em->width, g_em->height, TILEX, TILEY);
8792
8793         num_em_gfx_errors++;
8794       }
8795 #endif
8796
8797     }
8798   }
8799
8800   for (i = 0; i < TILE_MAX; i++)
8801   {
8802     for (j = 0; j < 8; j++)
8803     {
8804       int element = object_mapping[i].element_rnd;
8805       int action = object_mapping[i].action;
8806       int direction = object_mapping[i].direction;
8807       boolean is_backside = object_mapping[i].is_backside;
8808       int graphic_action  = el_act_dir2img(element, action, direction);
8809       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
8810
8811       if ((action == ACTION_SMASHED_BY_ROCK ||
8812            action == ACTION_SMASHED_BY_SPRING ||
8813            action == ACTION_EATING) &&
8814           graphic_action == graphic_default)
8815       {
8816         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
8817                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
8818                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
8819                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
8820                  Xspring);
8821
8822         /* no separate animation for "smashed by rock" -- use rock instead */
8823         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8824         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
8825
8826         g_em->bitmap            = g_xx->bitmap;
8827         g_em->src_x             = g_xx->src_x;
8828         g_em->src_y             = g_xx->src_y;
8829         g_em->src_offset_x      = g_xx->src_offset_x;
8830         g_em->src_offset_y      = g_xx->src_offset_y;
8831         g_em->dst_offset_x      = g_xx->dst_offset_x;
8832         g_em->dst_offset_y      = g_xx->dst_offset_y;
8833         g_em->width             = g_xx->width;
8834         g_em->height            = g_xx->height;
8835         g_em->unique_identifier = g_xx->unique_identifier;
8836
8837         if (!is_backside)
8838           g_em->preserve_background = TRUE;
8839       }
8840     }
8841   }
8842
8843   for (p = 0; p < MAX_PLAYERS; p++)
8844   {
8845     for (i = 0; i < SPR_MAX; i++)
8846     {
8847       int element = player_mapping[p][i].element_rnd;
8848       int action = player_mapping[p][i].action;
8849       int direction = player_mapping[p][i].direction;
8850
8851       for (j = 0; j < 8; j++)
8852       {
8853         int effective_element = element;
8854         int effective_action = action;
8855         int graphic = (direction == MV_NONE ?
8856                        el_act2img(effective_element, effective_action) :
8857                        el_act_dir2img(effective_element, effective_action,
8858                                       direction));
8859         struct GraphicInfo *g = &graphic_info[graphic];
8860         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
8861         Bitmap *src_bitmap;
8862         int src_x, src_y;
8863         int sync_frame = j;
8864
8865 #if DEBUG_EM_GFX
8866         Bitmap *debug_bitmap = g_em->bitmap;
8867         int debug_src_x = g_em->src_x;
8868         int debug_src_y = g_em->src_y;
8869 #endif
8870
8871         int frame = getAnimationFrame(g->anim_frames,
8872                                       g->anim_delay,
8873                                       g->anim_mode,
8874                                       g->anim_start_frame,
8875                                       sync_frame);
8876
8877         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
8878
8879         g_em->bitmap = src_bitmap;
8880         g_em->src_x = src_x;
8881         g_em->src_y = src_y;
8882         g_em->src_offset_x = 0;
8883         g_em->src_offset_y = 0;
8884         g_em->dst_offset_x = 0;
8885         g_em->dst_offset_y = 0;
8886         g_em->width  = TILEX;
8887         g_em->height = TILEY;
8888
8889 #if DEBUG_EM_GFX
8890
8891         /* skip check for EMC elements not contained in original EMC artwork */
8892         if (element == EL_PLAYER_3 ||
8893             element == EL_PLAYER_4)
8894           continue;
8895
8896         if (g_em->bitmap != debug_bitmap ||
8897             g_em->src_x != debug_src_x ||
8898             g_em->src_y != debug_src_y)
8899         {
8900           static int last_i = -1;
8901
8902           if (i != last_i)
8903           {
8904             printf("\n");
8905             last_i = i;
8906           }
8907
8908           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
8909                  p, i, element, element_info[element].token_name,
8910                  element_action_info[effective_action].suffix, direction);
8911
8912           if (element != effective_element)
8913             printf(" [%d ('%s')]",
8914                    effective_element,
8915                    element_info[effective_element].token_name);
8916
8917           printf("\n");
8918
8919           if (g_em->bitmap != debug_bitmap)
8920             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
8921                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
8922
8923           if (g_em->src_x != debug_src_x ||
8924               g_em->src_y != debug_src_y)
8925             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
8926                    j,
8927                    g_em->src_x, g_em->src_y,
8928                    g_em->src_x / 32, g_em->src_y / 32,
8929                    debug_src_x, debug_src_y,
8930                    debug_src_x / 32, debug_src_y / 32);
8931
8932           num_em_gfx_errors++;
8933         }
8934 #endif
8935
8936       }
8937     }
8938   }
8939
8940 #if DEBUG_EM_GFX
8941   printf("\n");
8942   printf("::: [%d errors found]\n", num_em_gfx_errors);
8943
8944   exit(0);
8945 #endif
8946 }
8947
8948 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
8949                             boolean any_player_moving,
8950                             boolean player_is_dropping)
8951 {
8952   if (tape.single_step && tape.recording && !tape.pausing)
8953   {
8954 #if 0
8955     boolean active_players = FALSE;
8956     int i;
8957
8958     for (i = 0; i < MAX_PLAYERS; i++)
8959       if (action[i] != JOY_NO_ACTION)
8960         active_players = TRUE;
8961 #endif
8962
8963     // if (frame == 0)
8964     if (frame == 0 && !player_is_dropping)
8965       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8966   }
8967 }
8968
8969 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
8970                             boolean murphy_is_dropping)
8971 {
8972 #if 0
8973   printf("::: waiting: %d, dropping: %d\n",
8974          murphy_is_waiting, murphy_is_dropping);
8975 #endif
8976
8977   if (tape.single_step && tape.recording && !tape.pausing)
8978   {
8979     // if (murphy_is_waiting || murphy_is_dropping)
8980     if (murphy_is_waiting)
8981     {
8982 #if 0
8983       printf("::: murphy is waiting -> pause mode\n");
8984 #endif
8985
8986       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
8987     }
8988   }
8989 }
8990
8991 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
8992                          int graphic, int sync_frame, int x, int y)
8993 {
8994   int frame = getGraphicAnimationFrame(graphic, sync_frame);
8995
8996   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
8997 }
8998
8999 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9000 {
9001   return (IS_NEXT_FRAME(sync_frame, graphic));
9002 }
9003
9004 int getGraphicInfo_Delay(int graphic)
9005 {
9006   return graphic_info[graphic].anim_delay;
9007 }
9008
9009 void PlayMenuSoundExt(int sound)
9010 {
9011   if (sound == SND_UNDEFINED)
9012     return;
9013
9014   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9015       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9016     return;
9017
9018   if (IS_LOOP_SOUND(sound))
9019     PlaySoundLoop(sound);
9020   else
9021     PlaySound(sound);
9022 }
9023
9024 void PlayMenuSound()
9025 {
9026   PlayMenuSoundExt(menu.sound[game_status]);
9027 }
9028
9029 void PlayMenuSoundStereo(int sound, int stereo_position)
9030 {
9031   if (sound == SND_UNDEFINED)
9032     return;
9033
9034   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9035       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9036     return;
9037
9038   if (IS_LOOP_SOUND(sound))
9039     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9040   else
9041     PlaySoundStereo(sound, stereo_position);
9042 }
9043
9044 void PlayMenuSoundIfLoopExt(int sound)
9045 {
9046   if (sound == SND_UNDEFINED)
9047     return;
9048
9049   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9050       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9051     return;
9052
9053   if (IS_LOOP_SOUND(sound))
9054     PlaySoundLoop(sound);
9055 }
9056
9057 void PlayMenuSoundIfLoop()
9058 {
9059   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9060 }
9061
9062 void PlayMenuMusicExt(int music)
9063 {
9064   if (music == MUS_UNDEFINED)
9065     return;
9066
9067   if (!setup.sound_music)
9068     return;
9069
9070   PlayMusic(music);
9071 }
9072
9073 void PlayMenuMusic()
9074 {
9075   PlayMenuMusicExt(menu.music[game_status]);
9076 }
9077
9078 void PlaySoundActivating()
9079 {
9080 #if 0
9081   PlaySound(SND_MENU_ITEM_ACTIVATING);
9082 #endif
9083 }
9084
9085 void PlaySoundSelecting()
9086 {
9087 #if 0
9088   PlaySound(SND_MENU_ITEM_SELECTING);
9089 #endif
9090 }
9091
9092 void ToggleFullscreenIfNeeded()
9093 {
9094   boolean change_fullscreen = (setup.fullscreen !=
9095                                video.fullscreen_enabled);
9096   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
9097                                     !strEqual(setup.fullscreen_mode,
9098                                               video.fullscreen_mode_current));
9099   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9100                                            setup.window_scaling_percent !=
9101                                            video.window_scaling_percent);
9102
9103   if (change_window_scaling_percent && video.fullscreen_enabled)
9104     return;
9105
9106   if (!change_window_scaling_percent && !video.fullscreen_available)
9107     return;
9108
9109 #if defined(TARGET_SDL2)
9110   if (change_window_scaling_percent)
9111   {
9112     SDLSetWindowScaling(setup.window_scaling_percent);
9113
9114     return;
9115   }
9116   else if (change_fullscreen)
9117   {
9118     SDLSetWindowFullscreen(setup.fullscreen);
9119
9120     /* set setup value according to successfully changed fullscreen mode */
9121     setup.fullscreen = video.fullscreen_enabled;
9122
9123     return;
9124   }
9125 #endif
9126
9127   if (change_fullscreen ||
9128       change_fullscreen_mode ||
9129       change_window_scaling_percent)
9130   {
9131     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9132
9133     /* save backbuffer content which gets lost when toggling fullscreen mode */
9134     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9135
9136     if (change_fullscreen_mode)
9137     {
9138       /* keep fullscreen, but change fullscreen mode (screen resolution) */
9139       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
9140     }
9141
9142     if (change_window_scaling_percent)
9143     {
9144       /* keep window mode, but change window scaling */
9145       video.fullscreen_enabled = TRUE;          /* force new window scaling */
9146     }
9147
9148     /* toggle fullscreen */
9149     ChangeVideoModeIfNeeded(setup.fullscreen);
9150
9151     /* set setup value according to successfully changed fullscreen mode */
9152     setup.fullscreen = video.fullscreen_enabled;
9153
9154     /* restore backbuffer content from temporary backbuffer backup bitmap */
9155     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9156
9157     FreeBitmap(tmp_backbuffer);
9158
9159 #if 1
9160     /* update visible window/screen */
9161     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9162 #else
9163     redraw_mask = REDRAW_ALL;
9164 #endif
9165   }
9166 }
9167
9168 void ChangeViewportPropertiesIfNeeded()
9169 {
9170   int *door_1_x = &DX;
9171   int *door_1_y = &DY;
9172   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9173   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9174   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9175                        game_status == GAME_MODE_EDITOR ? game_status :
9176                        GAME_MODE_MAIN);
9177   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9178   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9179   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
9180   int border_size = vp_playfield->border_size;
9181   int new_sx = vp_playfield->x + border_size;
9182   int new_sy = vp_playfield->y + border_size;
9183   int new_sxsize = vp_playfield->width  - 2 * border_size;
9184   int new_sysize = vp_playfield->height - 2 * border_size;
9185   int new_real_sx = vp_playfield->x;
9186   int new_real_sy = vp_playfield->y;
9187   int new_full_sxsize = vp_playfield->width;
9188   int new_full_sysize = vp_playfield->height;
9189 #if NEW_TILESIZE
9190   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
9191   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
9192                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
9193   int new_scr_fieldx = new_sxsize / tilesize;
9194   int new_scr_fieldy = new_sysize / tilesize;
9195   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
9196   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
9197 #else
9198   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
9199   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
9200 #endif
9201   boolean init_gfx_buffers = FALSE;
9202   boolean init_video_buffer = FALSE;
9203   boolean init_gadgets_and_toons = FALSE;
9204
9205 #if 0
9206   /* !!! TEST ONLY !!! */
9207   // InitGfxBuffers();
9208   return;
9209 #endif
9210
9211   if (viewport.window.width  != WIN_XSIZE ||
9212       viewport.window.height != WIN_YSIZE)
9213   {
9214     WIN_XSIZE = viewport.window.width;
9215     WIN_YSIZE = viewport.window.height;
9216
9217 #if 1
9218     init_video_buffer = TRUE;
9219     init_gfx_buffers = TRUE;
9220 #else
9221     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9222     InitGfxBuffers();
9223
9224 #if 1
9225     SetDrawDeactivationMask(REDRAW_NONE);
9226     SetDrawBackgroundMask(REDRAW_FIELD);
9227
9228     // RedrawBackground();
9229 #endif
9230 #endif
9231
9232     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
9233   }
9234
9235   if (new_scr_fieldx != SCR_FIELDX ||
9236       new_scr_fieldy != SCR_FIELDY)
9237   {
9238     /* this always toggles between MAIN and GAME when using small tile size */
9239
9240     SCR_FIELDX = new_scr_fieldx;
9241     SCR_FIELDY = new_scr_fieldy;
9242
9243     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
9244   }
9245
9246 #if 0
9247   if (new_tilesize_var != TILESIZE_VAR &&
9248       gfx_game_mode == GAME_MODE_PLAYING)
9249   {
9250     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
9251
9252     TILESIZE_VAR = new_tilesize_var;
9253
9254     init_gfx_buffers = TRUE;
9255
9256     // printf("::: tilesize: init_gfx_buffers\n");
9257   }
9258 #endif
9259
9260   if (new_sx != SX ||
9261       new_sy != SY ||
9262       new_sxsize != SXSIZE ||
9263       new_sysize != SYSIZE ||
9264       new_real_sx != REAL_SX ||
9265       new_real_sy != REAL_SY ||
9266       new_full_sxsize != FULL_SXSIZE ||
9267       new_full_sysize != FULL_SYSIZE ||
9268       new_tilesize_var != TILESIZE_VAR ||
9269       vp_door_1->x != *door_1_x ||
9270       vp_door_1->y != *door_1_y ||
9271       vp_door_2->x != *door_2_x ||
9272       vp_door_2->y != *door_2_y)
9273   {
9274     SX = new_sx;
9275     SY = new_sy;
9276     SXSIZE = new_sxsize;
9277     SYSIZE = new_sysize;
9278     REAL_SX = new_real_sx;
9279     REAL_SY = new_real_sy;
9280     FULL_SXSIZE = new_full_sxsize;
9281     FULL_SYSIZE = new_full_sysize;
9282     TILESIZE_VAR = new_tilesize_var;
9283
9284 #if 0
9285     printf("::: %d, %d, %d [%d]\n",
9286            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
9287            setup.small_game_graphics);
9288 #endif
9289
9290     *door_1_x = vp_door_1->x;
9291     *door_1_y = vp_door_1->y;
9292     *door_2_x = vp_door_2->x;
9293     *door_2_y = vp_door_2->y;
9294
9295 #if 1
9296     init_gfx_buffers = TRUE;
9297
9298     // printf("::: viewports: init_gfx_buffers\n");
9299 #else
9300     InitGfxBuffers();
9301 #endif
9302
9303     if (gfx_game_mode == GAME_MODE_MAIN)
9304     {
9305 #if 1
9306       init_gadgets_and_toons = TRUE;
9307
9308       // printf("::: viewports: init_gadgets_and_toons\n");
9309 #else
9310       InitGadgets();
9311       InitToons();
9312 #endif
9313     }
9314   }
9315
9316   if (init_gfx_buffers)
9317   {
9318     // printf("::: init_gfx_buffers\n");
9319
9320     SCR_FIELDX = new_scr_fieldx_buffers;
9321     SCR_FIELDY = new_scr_fieldy_buffers;
9322
9323     InitGfxBuffers();
9324
9325     SCR_FIELDX = new_scr_fieldx;
9326     SCR_FIELDY = new_scr_fieldy;
9327   }
9328
9329   if (init_video_buffer)
9330   {
9331     // printf("::: init_video_buffer\n");
9332
9333     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
9334
9335     SetDrawDeactivationMask(REDRAW_NONE);
9336     SetDrawBackgroundMask(REDRAW_FIELD);
9337   }
9338
9339   if (init_gadgets_and_toons)
9340   {
9341     // printf("::: init_gadgets_and_toons\n");
9342
9343     InitGadgets();
9344     InitToons();
9345   }
9346
9347 #if 0
9348   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
9349 #endif
9350 }