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