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