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