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