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