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