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