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