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