rnd-20140818-1-src
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "libgame/libgame.h"
17
18 #include "tools.h"
19 #include "init.h"
20 #include "game.h"
21 #include "events.h"
22 #include "cartoons.h"
23 #include "network.h"
24 #include "tape.h"
25 #include "screens.h"
26
27
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX    0
30
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES        0
33 #define TOOL_CTRL_ID_NO         1
34 #define TOOL_CTRL_ID_CONFIRM    2
35 #define TOOL_CTRL_ID_PLAYER_1   3
36 #define TOOL_CTRL_ID_PLAYER_2   4
37 #define TOOL_CTRL_ID_PLAYER_3   5
38 #define TOOL_CTRL_ID_PLAYER_4   6
39
40 #define NUM_TOOL_BUTTONS        7
41
42 /* constants for number of doors and door parts */
43 #define NUM_DOORS               2
44 #define NUM_PANELS              NUM_DOORS
45 // #define NUM_PANELS           0
46 #define MAX_PARTS_PER_DOOR      8
47 #define MAX_DOOR_PARTS          (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i)   ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49
50
51 struct DoorPartOrderInfo
52 {
53   int nr;
54   int sort_priority;
55 };
56
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58
59 struct DoorPartControlInfo
60 {
61   int door_token;
62   int graphic;
63   struct DoorPartPosInfo *pos;
64 };
65
66 static struct DoorPartControlInfo door_part_controls[] =
67 {
68   {
69     DOOR_1,
70     IMG_DOOR_1_GFX_PART_1,
71     &door_1.part_1
72   },
73   {
74     DOOR_1,
75     IMG_DOOR_1_GFX_PART_2,
76     &door_1.part_2
77   },
78   {
79     DOOR_1,
80     IMG_DOOR_1_GFX_PART_3,
81     &door_1.part_3
82   },
83   {
84     DOOR_1,
85     IMG_DOOR_1_GFX_PART_4,
86     &door_1.part_4
87   },
88   {
89     DOOR_1,
90     IMG_DOOR_1_GFX_PART_5,
91     &door_1.part_5
92   },
93   {
94     DOOR_1,
95     IMG_DOOR_1_GFX_PART_6,
96     &door_1.part_6
97   },
98   {
99     DOOR_1,
100     IMG_DOOR_1_GFX_PART_7,
101     &door_1.part_7
102   },
103   {
104     DOOR_1,
105     IMG_DOOR_1_GFX_PART_8,
106     &door_1.part_8
107   },
108
109   {
110     DOOR_2,
111     IMG_DOOR_2_GFX_PART_1,
112     &door_2.part_1
113   },
114   {
115     DOOR_2,
116     IMG_DOOR_2_GFX_PART_2,
117     &door_2.part_2
118   },
119   {
120     DOOR_2,
121     IMG_DOOR_2_GFX_PART_3,
122     &door_2.part_3
123   },
124   {
125     DOOR_2,
126     IMG_DOOR_2_GFX_PART_4,
127     &door_2.part_4
128   },
129   {
130     DOOR_2,
131     IMG_DOOR_2_GFX_PART_5,
132     &door_2.part_5
133   },
134   {
135     DOOR_2,
136     IMG_DOOR_2_GFX_PART_6,
137     &door_2.part_6
138   },
139   {
140     DOOR_2,
141     IMG_DOOR_2_GFX_PART_7,
142     &door_2.part_7
143   },
144   {
145     DOOR_2,
146     IMG_DOOR_2_GFX_PART_8,
147     &door_2.part_8
148   },
149
150   {
151     DOOR_1,
152     IMG_BACKGROUND_PANEL,
153     &door_1.panel
154   },
155   {
156     DOOR_2,
157     IMG_BACKGROUND_TAPE,
158     &door_2.panel
159   },
160
161   {
162     -1,
163     -1,
164     NULL
165   }
166 };
167
168
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
174
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
177
178 static char *print_if_not_empty(int element)
179 {
180   static char *s = NULL;
181   char *token_name = element_info[element].token_name;
182
183   if (s != NULL)
184     free(s);
185
186   s = checked_malloc(strlen(token_name) + 10 + 1);
187
188   if (element != EL_EMPTY)
189     sprintf(s, "%d\t['%s']", element, token_name);
190   else
191     sprintf(s, "%d", element);
192
193   return s;
194 }
195
196 void DumpTile(int x, int y)
197 {
198   int sx = SCREENX(x);
199   int sy = SCREENY(y);
200
201   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
202   {
203     x--;
204     y--;
205   }
206
207   printf_line("-", 79);
208   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209   printf_line("-", 79);
210
211   if (!IN_LEV_FIELD(x, y))
212   {
213     printf("(not in level field)\n");
214     printf("\n");
215
216     return;
217   }
218
219   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
220          element_info[Feld[x][y]].token_name);
221   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
222   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
223   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
224   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225   printf("  MovPos:      %d\n", MovPos[x][y]);
226   printf("  MovDir:      %d\n", MovDir[x][y]);
227   printf("  MovDelay:    %d\n", MovDelay[x][y]);
228   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
229   printf("  CustomValue: %d\n", CustomValue[x][y]);
230   printf("  GfxElement:  %d\n", GfxElement[x][y]);
231   printf("  GfxAction:   %d\n", GfxAction[x][y]);
232   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
233   printf("\n");
234 }
235
236 void SetDrawtoField(int mode)
237 {
238   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
239   {
240 #if NEW_TILESIZE
241 #if NEW_SCROLL
242     FX = 2 * TILEX_VAR;
243     FY = 2 * TILEY_VAR;
244     BX1 = -2;
245     BY1 = -2;
246     BX2 = SCR_FIELDX + 1;
247     BY2 = SCR_FIELDY + 1;
248     redraw_x1 = 2;
249     redraw_y1 = 2;
250 #else
251     FX = TILEX_VAR;
252     FY = TILEY_VAR;
253     BX1 = -1;
254     BY1 = -1;
255     BX2 = SCR_FIELDX;
256     BY2 = SCR_FIELDY;
257     redraw_x1 = 1;
258     redraw_y1 = 1;
259 #endif
260 #else
261 #if NEW_SCROLL
262     FX = 2 * TILEX;
263     FY = 2 * TILEY;
264     BX1 = -2;
265     BY1 = -2;
266     BX2 = SCR_FIELDX + 1;
267     BY2 = SCR_FIELDY + 1;
268     redraw_x1 = 2;
269     redraw_y1 = 2;
270 #else
271     FX = TILEX;
272     FY = TILEY;
273     BX1 = -1;
274     BY1 = -1;
275     BX2 = SCR_FIELDX;
276     BY2 = SCR_FIELDY;
277     redraw_x1 = 1;
278     redraw_y1 = 1;
279 #endif
280 #endif
281
282     drawto_field = fieldbuffer;
283   }
284   else  /* DRAW_BACKBUFFER */
285   {
286     FX = SX;
287     FY = SY;
288     BX1 = 0;
289     BY1 = 0;
290     BX2 = SCR_FIELDX - 1;
291     BY2 = SCR_FIELDY - 1;
292     redraw_x1 = 0;
293     redraw_y1 = 0;
294
295     drawto_field = backbuffer;
296   }
297 }
298
299 #if 1
300
301 static void RedrawPlayfield_RND()
302 {
303   if (game.envelope_active)
304     return;
305
306 #if 1
307   DrawLevel(REDRAW_ALL);
308 #else
309   int x, y;
310
311   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
312   // SetDrawBackgroundMask(REDRAW_FIELD);       // !!! CHECK THIS !!!
313   SetDrawBackgroundMask(REDRAW_ALL);    // !!! CHECK THIS !!!
314
315   for (x = BX1; x <= BX2; x++)
316     for (y = BY1; y <= BY2; y++)
317       DrawScreenField(x, y);
318
319   redraw_mask |= REDRAW_FIELD;
320 #endif
321   DrawAllPlayers();
322
323 #if 0
324 #if NEW_TILESIZE
325   BlitScreenToBitmap(backbuffer);
326 #else
327   /* blit playfield from scroll buffer to normal back buffer */
328   if (setup.soft_scrolling)
329   {
330     int fx = FX, fy = FY;
331
332     fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
333     fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
334
335     BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
336   }
337 #endif
338 #endif
339 }
340
341 void RedrawPlayfield()
342 {
343   if (game_status != GAME_MODE_PLAYING)
344     return;
345
346   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
347     RedrawPlayfield_EM(TRUE);
348   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
349     RedrawPlayfield_SP(TRUE);
350   else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
351     RedrawPlayfield_RND();
352
353   BlitScreenToBitmap(backbuffer);
354
355   BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
356              gfx.sx, gfx.sy);
357 }
358
359 #else
360
361 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
362 {
363   if (game_status == GAME_MODE_PLAYING &&
364       level.game_engine_type == GAME_ENGINE_TYPE_EM)
365   {
366     /* currently there is no partial redraw -- always redraw whole playfield */
367     RedrawPlayfield_EM(TRUE);
368
369     /* blit playfield from scroll buffer to normal back buffer for fading in */
370     BlitScreenToBitmap_EM(backbuffer);
371   }
372   else if (game_status == GAME_MODE_PLAYING &&
373            level.game_engine_type == GAME_ENGINE_TYPE_SP)
374   {
375     /* currently there is no partial redraw -- always redraw whole playfield */
376     RedrawPlayfield_SP(TRUE);
377
378     /* blit playfield from scroll buffer to normal back buffer for fading in */
379     BlitScreenToBitmap_SP(backbuffer);
380   }
381   else if (game_status == GAME_MODE_PLAYING &&
382            !game.envelope_active)
383   {
384     if (force_redraw)
385     {
386       x = gfx.sx - TILEX;
387       y = gfx.sy - TILEY;
388       width = gfx.sxsize + 2 * TILEX;
389       height = gfx.sysize + 2 * TILEY;
390     }
391
392     if (force_redraw)
393     {
394       int xx, yy;
395       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
396       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
397
398       for (xx = BX1; xx <= BX2; xx++)
399         for (yy = BY1; yy <= BY2; yy++)
400           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
401             DrawScreenField(xx, yy);
402       DrawAllPlayers();
403     }
404
405     if (setup.soft_scrolling)
406     {
407       int fx = FX, fy = FY;
408
409       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
410       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
411
412       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
413     }
414   }
415
416   if (force_redraw)
417   {
418     x = gfx.sx;
419     y = gfx.sy;
420     width = gfx.sxsize;
421     height = gfx.sysize;
422   }
423
424   BlitBitmap(drawto, window, x, y, width, height, x, y);
425 }
426
427 #endif
428
429 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
430 {
431   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
432
433   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
434   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
435 }
436
437 void DrawMaskedBorder_FIELD()
438 {
439   if (global.border_status >= GAME_MODE_TITLE &&
440       global.border_status <= GAME_MODE_PLAYING &&
441       border.draw_masked[global.border_status])
442     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
443 }
444
445 void DrawMaskedBorder_DOOR_1()
446 {
447   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
448       (global.border_status != GAME_MODE_EDITOR ||
449        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
450     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
451 }
452
453 void DrawMaskedBorder_DOOR_2()
454 {
455   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
456       global.border_status != GAME_MODE_EDITOR)
457     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
458 }
459
460 void DrawMaskedBorder_DOOR_3()
461 {
462   /* currently not available */
463 }
464
465 void DrawMaskedBorder_ALL()
466 {
467   DrawMaskedBorder_FIELD();
468   DrawMaskedBorder_DOOR_1();
469   DrawMaskedBorder_DOOR_2();
470   DrawMaskedBorder_DOOR_3();
471 }
472
473 void DrawMaskedBorder(int redraw_mask)
474 {
475   /* never draw masked screen borders on borderless screens */
476   if (effectiveGameStatus() == GAME_MODE_LOADING ||
477       effectiveGameStatus() == GAME_MODE_TITLE)
478     return;
479
480   /* never draw masked screen borders when displaying request outside door */
481   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
482       global.use_envelope_request)
483     return;
484
485   if (redraw_mask & REDRAW_ALL)
486     DrawMaskedBorder_ALL();
487   else
488   {
489     if (redraw_mask & REDRAW_FIELD)
490       DrawMaskedBorder_FIELD();
491     if (redraw_mask & REDRAW_DOOR_1)
492       DrawMaskedBorder_DOOR_1();
493     if (redraw_mask & REDRAW_DOOR_2)
494       DrawMaskedBorder_DOOR_2();
495     if (redraw_mask & REDRAW_DOOR_3)
496       DrawMaskedBorder_DOOR_3();
497   }
498 }
499
500 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
501 {
502   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
503   int fx = FX, fy = FY;
504   int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
505   int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
506
507 #if NEW_TILESIZE
508   int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
509   int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
510   int dx_var = dx * TILESIZE_VAR / TILESIZE;
511   int dy_var = dy * TILESIZE_VAR / TILESIZE;
512   int ffx, ffy;
513
514   // fx += dx * TILESIZE_VAR / TILESIZE;
515   // fy += dy * TILESIZE_VAR / TILESIZE;
516 #else
517   fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
518   fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
519 #endif
520
521   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
522   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
523
524   if (EVEN(SCR_FIELDX))
525   {
526     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
527       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
528     else
529       fx += (dx_var > 0 ? TILEX_VAR : 0);
530   }
531   else
532   {
533     fx += dx_var;
534   }
535
536   if (EVEN(SCR_FIELDY))
537   {
538     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
539       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
540     else
541       fy += (dy_var > 0 ? TILEY_VAR : 0);
542   }
543   else
544   {
545     fy += dy_var;
546   }
547
548 #if 0
549   printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
550          scroll_x, scroll_y,
551          SBX_Left, SBX_Right,
552          SBY_Upper, SBY_Lower,
553          fx, fy);
554 #endif
555
556 #if 1
557   if (full_lev_fieldx <= SCR_FIELDX)
558   {
559     // printf(":1: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
560
561     if (EVEN(SCR_FIELDX))
562       fx = 2 * TILEX_VAR - (ODD(lev_fieldx)  ? TILEX_VAR / 2 : 0);
563     else
564       fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
565
566     // printf(":2: PLAYFIELD FITS TO SCREEN [%d, %d, %d]\n", fx, ffx, dx_var);
567   }
568
569   if (full_lev_fieldy <= SCR_FIELDY)
570   {
571     if (EVEN(SCR_FIELDY))
572       fy = 2 * TILEY_VAR - (ODD(lev_fieldy)  ? TILEY_VAR / 2 : 0);
573     else
574       fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
575   }
576 #endif
577
578   if (border.draw_masked[GAME_MODE_PLAYING])
579   {
580     if (buffer != backbuffer)
581     {
582       /* copy playfield buffer to backbuffer to add masked border */
583       BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
584       DrawMaskedBorder(REDRAW_FIELD);
585     }
586
587     BlitBitmap(backbuffer, target_bitmap,
588                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
589                REAL_SX, REAL_SY);
590   }
591   else
592   {
593     BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
594   }
595 }
596
597 void BlitScreenToBitmap(Bitmap *target_bitmap)
598 {
599   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
600     BlitScreenToBitmap_EM(target_bitmap);
601   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
602     BlitScreenToBitmap_SP(target_bitmap);
603   else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
604     BlitScreenToBitmap_RND(target_bitmap);
605 }
606
607 void BackToFront()
608 {
609   int x, y;
610   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
611
612 #if 0
613   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
614   for (x = 0; x < SCR_FIELDX; x++)
615     for (y = 0 ; y < SCR_FIELDY; y++)
616       if (redraw[redraw_x1 + x][redraw_y1 + y])
617         printf("::: - %d, %d [%s]\n",
618                LEVELX(x), LEVELY(y),
619                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
620 #endif
621
622   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
623     redraw_mask |= REDRAW_FIELD;
624
625 #if 0
626   // never redraw single tiles, always redraw the whole field
627   // (redrawing single tiles up to a certain threshold was faster on old,
628   // now legacy graphics, but slows things down on modern graphics now)
629   // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
630   if (redraw_mask & REDRAW_TILES)
631     redraw_mask |= REDRAW_FIELD;
632 #endif
633
634 #if 0
635   /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
636   /* (force full redraw) */
637   if (game_status == GAME_MODE_PLAYING)
638     redraw_mask |= REDRAW_FIELD;
639 #endif
640
641   if (redraw_mask & REDRAW_FIELD)
642     redraw_mask &= ~REDRAW_TILES;
643
644   if (redraw_mask == REDRAW_NONE)
645     return;
646
647 #if 0
648   printf("::: ");
649   if (redraw_mask & REDRAW_ALL)
650     printf("[REDRAW_ALL]");
651   if (redraw_mask & REDRAW_FIELD)
652     printf("[REDRAW_FIELD]");
653   if (redraw_mask & REDRAW_TILES)
654     printf("[REDRAW_TILES]");
655   if (redraw_mask & REDRAW_DOOR_1)
656     printf("[REDRAW_DOOR_1]");
657   if (redraw_mask & REDRAW_DOOR_2)
658     printf("[REDRAW_DOOR_2]");
659   if (redraw_mask & REDRAW_FROM_BACKBUFFER)
660     printf("[REDRAW_FROM_BACKBUFFER]");
661   printf(" [%d]\n", FrameCounter);
662 #endif
663
664   if (redraw_mask & REDRAW_TILES &&
665       game_status == GAME_MODE_PLAYING &&
666       border.draw_masked[GAME_MODE_PLAYING])
667     redraw_mask |= REDRAW_FIELD;
668
669   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
670   {
671     static boolean last_frame_skipped = FALSE;
672     boolean skip_even_when_not_scrolling = TRUE;
673     boolean just_scrolling = (ScreenMovDir != 0);
674     boolean verbose = FALSE;
675
676     if (global.fps_slowdown_factor > 1 &&
677         (FrameCounter % global.fps_slowdown_factor) &&
678         (just_scrolling || skip_even_when_not_scrolling))
679     {
680       redraw_mask &= ~REDRAW_MAIN;
681
682       last_frame_skipped = TRUE;
683
684       if (verbose)
685         printf("FRAME SKIPPED\n");
686     }
687     else
688     {
689       if (last_frame_skipped)
690         redraw_mask |= REDRAW_FIELD;
691
692       last_frame_skipped = FALSE;
693
694       if (verbose)
695         printf("frame not skipped\n");
696     }
697   }
698
699   /* synchronize X11 graphics at this point; if we would synchronize the
700      display immediately after the buffer switching (after the XFlush),
701      this could mean that we have to wait for the graphics to complete,
702      although we could go on doing calculations for the next frame */
703
704   SyncDisplay();
705
706   /* never draw masked border to backbuffer when using playfield buffer */
707   if (game_status != GAME_MODE_PLAYING ||
708       redraw_mask & REDRAW_FROM_BACKBUFFER ||
709       buffer == backbuffer)
710     DrawMaskedBorder(redraw_mask);
711   else
712     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
713
714   if (redraw_mask & REDRAW_ALL)
715   {
716     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
717
718     redraw_mask = REDRAW_NONE;
719   }
720
721   if (redraw_mask & REDRAW_FIELD)
722   {
723 #if 0
724     printf("::: REDRAW_FIELD\n");
725 #endif
726
727     if (game_status != GAME_MODE_PLAYING ||
728         redraw_mask & REDRAW_FROM_BACKBUFFER)
729     {
730       BlitBitmap(backbuffer, window,
731                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
732     }
733     else
734     {
735 #if 1
736       BlitScreenToBitmap_RND(window);
737 #else
738       int fx = FX, fy = FY;
739
740 #if NEW_TILESIZE
741       int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
742       int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
743       int dx_var = dx * TILESIZE_VAR / TILESIZE;
744       int dy_var = dy * TILESIZE_VAR / TILESIZE;
745       int ffx, ffy;
746
747       // fx += dx * TILESIZE_VAR / TILESIZE;
748       // fy += dy * TILESIZE_VAR / TILESIZE;
749 #else
750       fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
751       fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
752 #endif
753
754       /* !!! THIS WORKS !!! */
755
756       printf("::: %d, %d\n", scroll_x, scroll_y);
757
758       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
759       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
760
761       if (EVEN(SCR_FIELDX))
762       {
763         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
764           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
765         else
766           fx += (dx > 0 ? TILEX_VAR : 0);
767       }
768       else
769       {
770         fx += dx;
771       }
772
773       if (EVEN(SCR_FIELDY))
774       {
775         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
776           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
777         else
778           fy += (dy > 0 ? TILEY_VAR : 0);
779       }
780       else
781       {
782         fy += dy;
783       }
784
785       if (border.draw_masked[GAME_MODE_PLAYING])
786       {
787         if (buffer != backbuffer)
788         {
789           /* copy playfield buffer to backbuffer to add masked border */
790           BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
791           DrawMaskedBorder(REDRAW_FIELD);
792         }
793
794         BlitBitmap(backbuffer, window,
795                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
796                    REAL_SX, REAL_SY);
797       }
798       else
799       {
800         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
801       }
802 #endif
803
804 #if 0
805 #ifdef DEBUG
806       printf("redrawing all (ScreenGfxPos == %d) because %s\n",
807              ScreenGfxPos,
808              (setup.soft_scrolling ?
809               "setup.soft_scrolling" :
810               ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
811               "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
812               ABS(ScreenGfxPos) == ScrollStepSize ?
813               "ABS(ScreenGfxPos) == ScrollStepSize" :
814               "redraw_tiles > REDRAWTILES_THRESHOLD"));
815 #endif
816 #endif
817     }
818
819     redraw_mask &= ~REDRAW_MAIN;
820   }
821
822   if (redraw_mask & REDRAW_DOORS)
823   {
824     if (redraw_mask & REDRAW_DOOR_1)
825       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
826
827     if (redraw_mask & REDRAW_DOOR_2)
828       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
829
830     if (redraw_mask & REDRAW_DOOR_3)
831       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
832
833     redraw_mask &= ~REDRAW_DOORS;
834   }
835
836   if (redraw_mask & REDRAW_MICROLEVEL)
837   {
838     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
839                SX, SY + 10 * TILEY);
840
841     redraw_mask &= ~REDRAW_MICROLEVEL;
842   }
843
844   if (redraw_mask & REDRAW_TILES)
845   {
846 #if 0
847     printf("::: REDRAW_TILES\n");
848 #endif
849
850 #if NEW_TILESIZE
851
852 #if 1
853     InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
854
855     {
856       int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
857       int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
858
859       int dx = 0, dy = 0;
860       int dx_var = dx * TILESIZE_VAR / TILESIZE;
861       int dy_var = dy * TILESIZE_VAR / TILESIZE;
862       int ffx, ffy;
863       int fx = FX, fy = FY;
864
865       int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
866       int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
867
868       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
869       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
870
871       if (EVEN(SCR_FIELDX))
872       {
873         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
874         {
875           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
876
877           if (fx % TILEX_VAR)
878             sx -= TILEX_VAR / 2;
879           else
880             sx -= TILEX_VAR;
881         }
882         else
883         {
884           fx += (dx_var > 0 ? TILEX_VAR : 0);
885         }
886       }
887
888       if (EVEN(SCR_FIELDY))
889       {
890         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
891         {
892           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
893
894           if (fy % TILEY_VAR)
895             sy -= TILEY_VAR / 2;
896           else
897             sy -= TILEY_VAR;
898         }
899         else
900         {
901           fy += (dy_var > 0 ? TILEY_VAR : 0);
902         }
903       }
904
905 #if 0
906       printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
907 #endif
908
909       for (x = 0; x < scr_fieldx; x++)
910         for (y = 0 ; y < scr_fieldy; y++)
911           if (redraw[redraw_x1 + x][redraw_y1 + y])
912             BlitBitmap(buffer, window,
913                        FX + x * TILEX_VAR, FY + y * TILEY_VAR,
914                        TILEX_VAR, TILEY_VAR,
915                        sx + x * TILEX_VAR, sy + y * TILEY_VAR);
916     }
917
918     InitGfxClipRegion(FALSE, -1, -1, -1, -1);
919 #else
920     for (x = 0; x < SCR_FIELDX; x++)
921       for (y = 0 ; y < SCR_FIELDY; y++)
922         if (redraw[redraw_x1 + x][redraw_y1 + y])
923           BlitBitmap(buffer, window,
924                      FX + x * TILEX_VAR, FY + y * TILEY_VAR,
925                      TILEX_VAR, TILEY_VAR,
926                      SX + x * TILEX_VAR, SY + y * TILEY_VAR);
927 #endif
928
929 #else
930     for (x = 0; x < SCR_FIELDX; x++)
931       for (y = 0 ; y < SCR_FIELDY; y++)
932         if (redraw[redraw_x1 + x][redraw_y1 + y])
933           BlitBitmap(buffer, window,
934                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
935                      SX + x * TILEX, SY + y * TILEY);
936 #endif
937   }
938
939   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
940   {
941     char text[100];
942     char info1[100];
943
944     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
945     if (!global.fps_slowdown)
946       info1[0] = '\0';
947
948     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
949 #if 1
950     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
951 #else
952     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
953 #endif
954   }
955
956   FlushDisplay();
957
958   for (x = 0; x < MAX_BUF_XSIZE; x++)
959     for (y = 0; y < MAX_BUF_YSIZE; y++)
960       redraw[x][y] = 0;
961   redraw_tiles = 0;
962   redraw_mask = REDRAW_NONE;
963 }
964
965 static void FadeCrossSaveBackbuffer()
966 {
967   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
968 }
969
970 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
971 {
972   static int fade_type_skip = FADE_TYPE_NONE;
973   void (*draw_border_function)(void) = NULL;
974   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
975   int x, y, width, height;
976   int fade_delay, post_delay;
977
978   if (fade_type == FADE_TYPE_FADE_OUT)
979   {
980     if (fade_type_skip != FADE_TYPE_NONE)
981     {
982 #if 0
983       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
984 #endif
985
986       /* skip all fade operations until specified fade operation */
987       if (fade_type & fade_type_skip)
988         fade_type_skip = FADE_TYPE_NONE;
989
990       return;
991     }
992
993     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
994     {
995       FadeCrossSaveBackbuffer();
996
997       return;
998     }
999   }
1000
1001   redraw_mask |= fade_mask;
1002
1003   if (fade_type == FADE_TYPE_SKIP)
1004   {
1005 #if 0
1006     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
1007 #endif
1008
1009     fade_type_skip = fade_mode;
1010
1011     return;
1012   }
1013
1014 #if 0
1015   printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
1016          fade_type_skip);
1017 #endif
1018
1019 #if 1
1020   fade_delay = fading.fade_delay;
1021   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1022 #endif
1023
1024   if (fade_type_skip != FADE_TYPE_NONE)
1025   {
1026 #if 0
1027     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
1028 #endif
1029
1030     /* skip all fade operations until specified fade operation */
1031     if (fade_type & fade_type_skip)
1032       fade_type_skip = FADE_TYPE_NONE;
1033
1034 #if 1
1035     fade_delay = 0;
1036 #else
1037     return;
1038 #endif
1039   }
1040
1041 #if 1
1042   if (global.autoplay_leveldir)
1043   {
1044     // fading.fade_mode = FADE_MODE_NONE;
1045
1046     return;
1047   }
1048 #endif
1049
1050 #if 0
1051   if (fading.fade_mode == FADE_MODE_NONE)
1052   {
1053     BackToFront();
1054
1055     return;
1056   }
1057 #endif
1058
1059   /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
1060
1061 #if 0
1062   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
1063 #endif
1064
1065 #if 0
1066   if (fade_mask == REDRAW_NONE)
1067     fade_mask = REDRAW_FIELD;
1068 #endif
1069
1070   // if (fade_mask & REDRAW_FIELD)
1071   if (fade_mask == REDRAW_FIELD)
1072   {
1073     x = REAL_SX;
1074     y = REAL_SY;
1075     width  = FULL_SXSIZE;
1076     height = FULL_SYSIZE;
1077
1078 #if 0
1079     fade_delay = fading.fade_delay;
1080     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1081 #endif
1082
1083     if (border.draw_masked_when_fading)
1084       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
1085     else
1086       DrawMaskedBorder_FIELD();                         /* draw once */
1087   }
1088   else          /* REDRAW_ALL */
1089   {
1090     x = 0;
1091     y = 0;
1092     width  = WIN_XSIZE;
1093     height = WIN_YSIZE;
1094
1095 #if 0
1096     fade_delay = fading.fade_delay;
1097     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1098 #endif
1099   }
1100
1101 #if 1
1102   if (!setup.fade_screens ||
1103       fade_delay == 0 ||
1104       fading.fade_mode == FADE_MODE_NONE)
1105 #else
1106   if (!setup.fade_screens || fade_delay == 0)
1107 #endif
1108   {
1109     if (fade_mode == FADE_MODE_FADE_OUT)
1110       return;
1111
1112 #if 0
1113     if (fade_mode == FADE_MODE_FADE_OUT &&
1114         fading.fade_mode != FADE_MODE_NONE)
1115       ClearRectangle(backbuffer, x, y, width, height);
1116 #endif
1117
1118 #if 1
1119
1120 #if 1
1121     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1122
1123     redraw_mask &= ~fade_mask;
1124 #else
1125     /* always redraw area that was explicitly marked to fade */
1126     redraw_mask |= fade_mask;
1127
1128     BackToFront();
1129 #endif
1130
1131 #else
1132
1133 #if 1
1134     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1135     redraw_mask = REDRAW_NONE;
1136     // (^^^ WRONG; should be "redraw_mask &= ~fade_mask" if done this way)
1137 #else
1138     BackToFront();
1139 #endif
1140 #endif
1141
1142     return;
1143   }
1144
1145   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1146                 draw_border_function);
1147
1148   redraw_mask &= ~fade_mask;
1149 }
1150
1151 void FadeIn(int fade_mask)
1152 {
1153   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1154     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1155   else
1156     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1157 }
1158
1159 void FadeOut(int fade_mask)
1160 {
1161   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1162     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1163   else
1164     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1165
1166   global.border_status = game_status;
1167 }
1168
1169 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1170 {
1171   static struct TitleFadingInfo fading_leave_stored;
1172
1173   if (set)
1174     fading_leave_stored = fading_leave;
1175   else
1176     fading = fading_leave_stored;
1177 }
1178
1179 void FadeSetEnterMenu()
1180 {
1181   fading = menu.enter_menu;
1182
1183 #if 0
1184   printf("::: storing enter_menu\n");
1185 #endif
1186
1187   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1188 }
1189
1190 void FadeSetLeaveMenu()
1191 {
1192   fading = menu.leave_menu;
1193
1194 #if 0
1195   printf("::: storing leave_menu\n");
1196 #endif
1197
1198   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1199 }
1200
1201 void FadeSetEnterScreen()
1202 {
1203   fading = menu.enter_screen[game_status];
1204
1205 #if 0
1206   printf("::: storing leave_screen[%d]\n", game_status);
1207 #endif
1208
1209   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
1210 }
1211
1212 void FadeSetNextScreen()
1213 {
1214   fading = menu.next_screen;
1215
1216 #if 0
1217   printf("::: storing next_screen\n");
1218 #endif
1219
1220   // (do not overwrite fade mode set by FadeSetEnterScreen)
1221   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
1222 }
1223
1224 void FadeSetLeaveScreen()
1225 {
1226 #if 0
1227   printf("::: recalling last stored value\n");
1228 #endif
1229
1230   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
1231 }
1232
1233 void FadeSetFromType(int type)
1234 {
1235   if (type & TYPE_ENTER_SCREEN)
1236     FadeSetEnterScreen();
1237   else if (type & TYPE_ENTER)
1238     FadeSetEnterMenu();
1239   else if (type & TYPE_LEAVE)
1240     FadeSetLeaveMenu();
1241 }
1242
1243 void FadeSetDisabled()
1244 {
1245   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1246
1247   fading = fading_none;
1248 }
1249
1250 void FadeSkipNextFadeIn()
1251 {
1252   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1253 }
1254
1255 void FadeSkipNextFadeOut()
1256 {
1257   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1258 }
1259
1260 void SetWindowBackgroundImageIfDefined(int graphic)
1261 {
1262   if (graphic_info[graphic].bitmap)
1263     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1264 }
1265
1266 void SetMainBackgroundImageIfDefined(int graphic)
1267 {
1268   if (graphic_info[graphic].bitmap)
1269     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1270 }
1271
1272 void SetDoorBackgroundImageIfDefined(int graphic)
1273 {
1274   if (graphic_info[graphic].bitmap)
1275     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1276 }
1277
1278 void SetWindowBackgroundImage(int graphic)
1279 {
1280   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1281                             graphic_info[graphic].bitmap ?
1282                             graphic_info[graphic].bitmap :
1283                             graphic_info[IMG_BACKGROUND].bitmap);
1284 }
1285
1286 void SetMainBackgroundImage(int graphic)
1287 {
1288   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1289                           graphic_info[graphic].bitmap ?
1290                           graphic_info[graphic].bitmap :
1291                           graphic_info[IMG_BACKGROUND].bitmap);
1292 }
1293
1294 void SetDoorBackgroundImage(int graphic)
1295 {
1296   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1297                           graphic_info[graphic].bitmap ?
1298                           graphic_info[graphic].bitmap :
1299                           graphic_info[IMG_BACKGROUND].bitmap);
1300 }
1301
1302 void SetPanelBackground()
1303 {
1304 #if 1
1305   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1306
1307 #if 1
1308   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1309                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1310 #else
1311   /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1312   ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1313   BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1314              MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1315 #endif
1316 #else
1317   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1318              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1319 #endif
1320
1321   SetDoorBackgroundBitmap(bitmap_db_panel);
1322 }
1323
1324 void DrawBackground(int x, int y, int width, int height)
1325 {
1326   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1327   /* (when entering hall of fame after playing) */
1328 #if 0
1329   ClearRectangleOnBackground(drawto, x, y, width, height);
1330 #else
1331   ClearRectangleOnBackground(backbuffer, x, y, width, height);
1332 #endif
1333
1334 #if 1
1335
1336 #if 1
1337   if (IN_GFX_FIELD_FULL(x, y))
1338     redraw_mask |= REDRAW_FIELD;
1339   else if (IN_GFX_DOOR_1(x, y))
1340     redraw_mask |= REDRAW_DOOR_1;
1341   else if (IN_GFX_DOOR_2(x, y))
1342     redraw_mask |= REDRAW_DOOR_2;
1343   else if (IN_GFX_DOOR_3(x, y))
1344     redraw_mask |= REDRAW_DOOR_3;
1345 #else
1346   /* (this only works for the current arrangement of playfield and panels) */
1347   if (x < gfx.dx)
1348     redraw_mask |= REDRAW_FIELD;
1349   else if (y < gfx.vy)
1350     redraw_mask |= REDRAW_DOOR_1;
1351   else
1352     redraw_mask |= REDRAW_DOOR_2;
1353 #endif
1354
1355 #else
1356   /* (this is just wrong (when drawing to one of the two door panel areas)) */
1357   redraw_mask |= REDRAW_FIELD;
1358 #endif
1359 }
1360
1361 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1362 {
1363   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1364
1365   if (font->bitmap == NULL)
1366     return;
1367
1368   DrawBackground(x, y, width, height);
1369 }
1370
1371 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1372 {
1373   struct GraphicInfo *g = &graphic_info[graphic];
1374
1375   if (g->bitmap == NULL)
1376     return;
1377
1378   DrawBackground(x, y, width, height);
1379 }
1380
1381 void ClearField()
1382 {
1383   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1384   /* (when entering hall of fame after playing) */
1385   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1386
1387   /* !!! maybe this should be done before clearing the background !!! */
1388   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1389   {
1390     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1391     SetDrawtoField(DRAW_BUFFERED);
1392   }
1393   else
1394     SetDrawtoField(DRAW_BACKBUFFER);
1395 }
1396
1397 void MarkTileDirty(int x, int y)
1398 {
1399   int xx = redraw_x1 + x;
1400   int yy = redraw_y1 + y;
1401
1402   if (!redraw[xx][yy])
1403     redraw_tiles++;
1404
1405   redraw[xx][yy] = TRUE;
1406   redraw_mask |= REDRAW_TILES;
1407 }
1408
1409 void SetBorderElement()
1410 {
1411   int x, y;
1412
1413   BorderElement = EL_EMPTY;
1414
1415   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1416   {
1417     for (x = 0; x < lev_fieldx; x++)
1418     {
1419       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1420         BorderElement = EL_STEELWALL;
1421
1422       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1423         x = lev_fieldx - 2;
1424     }
1425   }
1426 }
1427
1428 void FloodFillLevel(int from_x, int from_y, int fill_element,
1429                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1430                     int max_fieldx, int max_fieldy)
1431 {
1432   int i,x,y;
1433   int old_element;
1434   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1435   static int safety = 0;
1436
1437   /* check if starting field still has the desired content */
1438   if (field[from_x][from_y] == fill_element)
1439     return;
1440
1441   safety++;
1442
1443   if (safety > max_fieldx * max_fieldy)
1444     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1445
1446   old_element = field[from_x][from_y];
1447   field[from_x][from_y] = fill_element;
1448
1449   for (i = 0; i < 4; i++)
1450   {
1451     x = from_x + check[i][0];
1452     y = from_y + check[i][1];
1453
1454     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1455       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1456   }
1457
1458   safety--;
1459 }
1460
1461 void SetRandomAnimationValue(int x, int y)
1462 {
1463   gfx.anim_random_frame = GfxRandom[x][y];
1464 }
1465
1466 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1467 {
1468   /* animation synchronized with global frame counter, not move position */
1469   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1470     sync_frame = FrameCounter;
1471
1472   return getAnimationFrame(graphic_info[graphic].anim_frames,
1473                            graphic_info[graphic].anim_delay,
1474                            graphic_info[graphic].anim_mode,
1475                            graphic_info[graphic].anim_start_frame,
1476                            sync_frame);
1477 }
1478
1479 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1480                               Bitmap **bitmap, int *x, int *y,
1481                               boolean get_backside)
1482 {
1483   struct
1484   {
1485     int width_mult, width_div;
1486     int height_mult, height_div;
1487   }
1488   offset_calc[6] =
1489   {
1490     { 15, 16,   2, 3    },      /* 1 x 1 */
1491     { 7, 8,     2, 3    },      /* 2 x 2 */
1492     { 3, 4,     2, 3    },      /* 4 x 4 */
1493     { 1, 2,     2, 3    },      /* 8 x 8 */
1494     { 0, 1,     2, 3    },      /* 16 x 16 */
1495     { 0, 1,     0, 1    },      /* 32 x 32 */
1496   };
1497   struct GraphicInfo *g = &graphic_info[graphic];
1498   Bitmap *src_bitmap = g->bitmap;
1499   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1500   int offset_calc_pos = log_2(tilesize);
1501   int width_mult  = offset_calc[offset_calc_pos].width_mult;
1502   int width_div   = offset_calc[offset_calc_pos].width_div;
1503   int height_mult = offset_calc[offset_calc_pos].height_mult;
1504   int height_div  = offset_calc[offset_calc_pos].height_div;
1505   int startx = src_bitmap->width * width_mult / width_div;
1506   int starty = src_bitmap->height * height_mult / height_div;
1507 #if NEW_TILESIZE
1508   int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1509     tilesize / TILESIZE;
1510   int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1511     tilesize / TILESIZE;
1512 #else
1513   int src_x = g->src_x * tilesize / TILESIZE;
1514   int src_y = g->src_y * tilesize / TILESIZE;
1515 #endif
1516   int width = g->width * tilesize / TILESIZE;
1517   int height = g->height * tilesize / TILESIZE;
1518   int offset_x = g->offset_x * tilesize / TILESIZE;
1519   int offset_y = g->offset_y * tilesize / TILESIZE;
1520
1521   if (g->offset_y == 0)         /* frames are ordered horizontally */
1522   {
1523     int max_width = g->anim_frames_per_line * width;
1524     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1525
1526     src_x = pos % max_width;
1527     src_y = src_y % height + pos / max_width * height;
1528   }
1529   else if (g->offset_x == 0)    /* frames are ordered vertically */
1530   {
1531     int max_height = g->anim_frames_per_line * height;
1532     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1533
1534     src_x = src_x % width + pos / max_height * width;
1535     src_y = pos % max_height;
1536   }
1537   else                          /* frames are ordered diagonally */
1538   {
1539     src_x = src_x + frame * offset_x;
1540     src_y = src_y + frame * offset_y;
1541   }
1542
1543   *bitmap = src_bitmap;
1544   *x = startx + src_x;
1545   *y = starty + src_y;
1546 }
1547
1548 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1549                               int *x, int *y, boolean get_backside)
1550 {
1551   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1552                            get_backside);
1553 }
1554
1555 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1556                            Bitmap **bitmap, int *x, int *y)
1557 {
1558   getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1559 }
1560
1561 void getFixedGraphicSource(int graphic, int frame,
1562                            Bitmap **bitmap, int *x, int *y)
1563 {
1564   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1565 }
1566
1567 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1568 {
1569 #if 1
1570   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1571 #else
1572   struct GraphicInfo *g = &graphic_info[graphic];
1573   int mini_startx = 0;
1574   int mini_starty = g->bitmap->height * 2 / 3;
1575
1576   *bitmap = g->bitmap;
1577   *x = mini_startx + g->src_x / 2;
1578   *y = mini_starty + g->src_y / 2;
1579 #endif
1580 }
1581
1582 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1583                                 int *x, int *y, boolean get_backside)
1584 {
1585   struct GraphicInfo *g = &graphic_info[graphic];
1586   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1587   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1588
1589 #if NEW_TILESIZE
1590
1591   if (TILESIZE_VAR != TILESIZE)
1592     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1593                                     get_backside);
1594 #endif
1595
1596   *bitmap = g->bitmap;
1597
1598   if (g->offset_y == 0)         /* frames are ordered horizontally */
1599   {
1600     int max_width = g->anim_frames_per_line * g->width;
1601     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1602
1603     *x = pos % max_width;
1604     *y = src_y % g->height + pos / max_width * g->height;
1605   }
1606   else if (g->offset_x == 0)    /* frames are ordered vertically */
1607   {
1608     int max_height = g->anim_frames_per_line * g->height;
1609     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1610
1611     *x = src_x % g->width + pos / max_height * g->width;
1612     *y = pos % max_height;
1613   }
1614   else                          /* frames are ordered diagonally */
1615   {
1616     *x = src_x + frame * g->offset_x;
1617     *y = src_y + frame * g->offset_y;
1618   }
1619 }
1620
1621 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1622 {
1623   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1624 }
1625
1626 void DrawGraphic(int x, int y, int graphic, int frame)
1627 {
1628 #if DEBUG
1629   if (!IN_SCR_FIELD(x, y))
1630   {
1631     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1632     printf("DrawGraphic(): This should never happen!\n");
1633     return;
1634   }
1635 #endif
1636
1637 #if NEW_TILESIZE
1638   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1639                  frame);
1640 #else
1641   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1642 #endif
1643   MarkTileDirty(x, y);
1644 }
1645
1646 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1647 {
1648 #if DEBUG
1649   if (!IN_SCR_FIELD(x, y))
1650   {
1651     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1652     printf("DrawGraphic(): This should never happen!\n");
1653     return;
1654   }
1655 #endif
1656
1657   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1658                       frame);
1659   MarkTileDirty(x, y);
1660 }
1661
1662 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1663                     int frame)
1664 {
1665   Bitmap *src_bitmap;
1666   int src_x, src_y;
1667
1668   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1669 #if NEW_TILESIZE
1670   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1671 #else
1672   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1673 #endif
1674 }
1675
1676 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1677                          int frame)
1678 {
1679   Bitmap *src_bitmap;
1680   int src_x, src_y;
1681
1682   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1683   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1684 }
1685
1686 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1687 {
1688 #if DEBUG
1689   if (!IN_SCR_FIELD(x, y))
1690   {
1691     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1692     printf("DrawGraphicThruMask(): This should never happen!\n");
1693     return;
1694   }
1695 #endif
1696
1697 #if NEW_TILESIZE
1698   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1699                          graphic, frame);
1700 #else
1701   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1702                          frame);
1703 #endif
1704   MarkTileDirty(x, y);
1705 }
1706
1707 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1708 {
1709 #if DEBUG
1710   if (!IN_SCR_FIELD(x, y))
1711   {
1712     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1713     printf("DrawGraphicThruMask(): This should never happen!\n");
1714     return;
1715   }
1716 #endif
1717
1718   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1719                               graphic, frame);
1720   MarkTileDirty(x, y);
1721 }
1722
1723 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1724                             int frame)
1725 {
1726   Bitmap *src_bitmap;
1727   int src_x, src_y;
1728
1729   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1730
1731   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1732                 dst_x - src_x, dst_y - src_y);
1733 #if NEW_TILESIZE
1734   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1735                    dst_x, dst_y);
1736 #else
1737   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1738 #endif
1739 }
1740
1741 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1742                                  int graphic, int frame)
1743 {
1744   Bitmap *src_bitmap;
1745   int src_x, src_y;
1746
1747   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1748
1749   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1750                 dst_x - src_x, dst_y - src_y);
1751   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1752 }
1753
1754 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1755 {
1756   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1757                       frame, tilesize);
1758   MarkTileDirty(x / tilesize, y / tilesize);
1759 }
1760
1761 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1762                          int tilesize)
1763 {
1764   Bitmap *src_bitmap;
1765   int src_x, src_y;
1766
1767   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1768   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1769 }
1770
1771 void DrawMiniGraphic(int x, int y, int graphic)
1772 {
1773   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1774   MarkTileDirty(x / 2, y / 2);
1775 }
1776
1777 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1778 {
1779   Bitmap *src_bitmap;
1780   int src_x, src_y;
1781
1782   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1783   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1784 }
1785
1786 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1787                                             int graphic, int frame,
1788                                             int cut_mode, int mask_mode)
1789 {
1790   Bitmap *src_bitmap;
1791   int src_x, src_y;
1792   int dst_x, dst_y;
1793   int width = TILEX, height = TILEY;
1794   int cx = 0, cy = 0;
1795
1796   if (dx || dy)                 /* shifted graphic */
1797   {
1798     if (x < BX1)                /* object enters playfield from the left */
1799     {
1800       x = BX1;
1801       width = dx;
1802       cx = TILEX - dx;
1803       dx = 0;
1804     }
1805     else if (x > BX2)           /* object enters playfield from the right */
1806     {
1807       x = BX2;
1808       width = -dx;
1809       dx = TILEX + dx;
1810     }
1811     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1812     {
1813       width += dx;
1814       cx = -dx;
1815       dx = 0;
1816     }
1817     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1818       width -= dx;
1819     else if (dx)                /* general horizontal movement */
1820       MarkTileDirty(x + SIGN(dx), y);
1821
1822     if (y < BY1)                /* object enters playfield from the top */
1823     {
1824       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1825         return;
1826
1827       y = BY1;
1828       height = dy;
1829       cy = TILEY - dy;
1830       dy = 0;
1831     }
1832     else if (y > BY2)           /* object enters playfield from the bottom */
1833     {
1834       y = BY2;
1835       height = -dy;
1836       dy = TILEY + dy;
1837     }
1838     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1839     {
1840       height += dy;
1841       cy = -dy;
1842       dy = 0;
1843     }
1844     else if (dy > 0 && cut_mode == CUT_ABOVE)
1845     {
1846       if (y == BY2)             /* object completely above bottom border */
1847         return;
1848
1849       height = dy;
1850       cy = TILEY - dy;
1851       dy = TILEY;
1852       MarkTileDirty(x, y + 1);
1853     }                           /* object leaves playfield to the bottom */
1854     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1855       height -= dy;
1856     else if (dy)                /* general vertical movement */
1857       MarkTileDirty(x, y + SIGN(dy));
1858   }
1859
1860 #if DEBUG
1861   if (!IN_SCR_FIELD(x, y))
1862   {
1863     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1864     printf("DrawGraphicShifted(): This should never happen!\n");
1865     return;
1866   }
1867 #endif
1868
1869 #if NEW_TILESIZE
1870   width = width * TILESIZE_VAR / TILESIZE;
1871   height = height * TILESIZE_VAR / TILESIZE;
1872   cx = cx * TILESIZE_VAR / TILESIZE;
1873   cy = cy * TILESIZE_VAR / TILESIZE;
1874   dx = dx * TILESIZE_VAR / TILESIZE;
1875   dy = dy * TILESIZE_VAR / TILESIZE;
1876 #endif
1877
1878   if (width > 0 && height > 0)
1879   {
1880     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1881
1882     src_x += cx;
1883     src_y += cy;
1884
1885 #if NEW_TILESIZE
1886     dst_x = FX + x * TILEX_VAR + dx;
1887     dst_y = FY + y * TILEY_VAR + dy;
1888 #else
1889     dst_x = FX + x * TILEX + dx;
1890     dst_y = FY + y * TILEY + dy;
1891 #endif
1892
1893     if (mask_mode == USE_MASKING)
1894     {
1895       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1896                     dst_x - src_x, dst_y - src_y);
1897       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1898                        dst_x, dst_y);
1899     }
1900     else
1901       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1902                  dst_x, dst_y);
1903
1904     MarkTileDirty(x, y);
1905   }
1906 }
1907
1908 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1909                                             int graphic, int frame,
1910                                             int cut_mode, int mask_mode)
1911 {
1912   Bitmap *src_bitmap;
1913   int src_x, src_y;
1914   int dst_x, dst_y;
1915 #if NEW_TILESIZE
1916   int width = TILEX_VAR, height = TILEY_VAR;
1917 #else
1918   int width = TILEX, height = TILEY;
1919 #endif
1920   int x1 = x;
1921   int y1 = y;
1922   int x2 = x + SIGN(dx);
1923   int y2 = y + SIGN(dy);
1924 #if 0
1925   /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1926   int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1927 #else
1928   /* movement with two-tile animations must be sync'ed with movement position,
1929      not with current GfxFrame (which can be higher when using slow movement) */
1930   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1931   int anim_frames = graphic_info[graphic].anim_frames;
1932 #if 1
1933   /* (we also need anim_delay here for movement animations with less frames) */
1934   int anim_delay = graphic_info[graphic].anim_delay;
1935   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1936 #else
1937   int sync_frame = anim_pos * anim_frames / TILESIZE;
1938 #endif
1939 #endif
1940   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1941   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1942
1943   /* re-calculate animation frame for two-tile movement animation */
1944   frame = getGraphicAnimationFrame(graphic, sync_frame);
1945
1946 #if 0
1947 #if 0
1948   printf("::: %d, %d, %d => %d [%d]\n",
1949          anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1950 #else
1951   printf("::: %d, %d => %d\n",
1952          anim_pos, anim_frames, sync_frame);
1953 #endif
1954 #endif
1955
1956 #if 0
1957   printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1958          GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1959 #endif
1960
1961   /* check if movement start graphic inside screen area and should be drawn */
1962   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1963   {
1964     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1965
1966 #if NEW_TILESIZE
1967     dst_x = FX + x1 * TILEX_VAR;
1968     dst_y = FY + y1 * TILEY_VAR;
1969 #else
1970     dst_x = FX + x1 * TILEX;
1971     dst_y = FY + y1 * TILEY;
1972 #endif
1973
1974     if (mask_mode == USE_MASKING)
1975     {
1976       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1977                     dst_x - src_x, dst_y - src_y);
1978       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1979                        dst_x, dst_y);
1980     }
1981     else
1982       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1983                  dst_x, dst_y);
1984
1985     MarkTileDirty(x1, y1);
1986   }
1987
1988   /* check if movement end graphic inside screen area and should be drawn */
1989   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1990   {
1991     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1992
1993 #if NEW_TILESIZE
1994     dst_x = FX + x2 * TILEX_VAR;
1995     dst_y = FY + y2 * TILEY_VAR;
1996 #else
1997     dst_x = FX + x2 * TILEX;
1998     dst_y = FY + y2 * TILEY;
1999 #endif
2000
2001     if (mask_mode == USE_MASKING)
2002     {
2003       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2004                     dst_x - src_x, dst_y - src_y);
2005       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
2006                        dst_x, dst_y);
2007     }
2008     else
2009       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
2010                  dst_x, dst_y);
2011
2012     MarkTileDirty(x2, y2);
2013   }
2014 }
2015
2016 static void DrawGraphicShifted(int x, int y, int dx, int dy,
2017                                int graphic, int frame,
2018                                int cut_mode, int mask_mode)
2019 {
2020   if (graphic < 0)
2021   {
2022     DrawGraphic(x, y, graphic, frame);
2023
2024     return;
2025   }
2026
2027   if (graphic_info[graphic].double_movement)    /* EM style movement images */
2028     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2029   else
2030     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
2031 }
2032
2033 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
2034                                 int frame, int cut_mode)
2035 {
2036   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
2037 }
2038
2039 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
2040                           int cut_mode, int mask_mode)
2041 {
2042   int lx = LEVELX(x), ly = LEVELY(y);
2043   int graphic;
2044   int frame;
2045
2046   if (IN_LEV_FIELD(lx, ly))
2047   {
2048     SetRandomAnimationValue(lx, ly);
2049
2050     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
2051     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2052
2053     /* do not use double (EM style) movement graphic when not moving */
2054     if (graphic_info[graphic].double_movement && !dx && !dy)
2055     {
2056       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
2057       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
2058     }
2059   }
2060   else  /* border element */
2061   {
2062     graphic = el2img(element);
2063     frame = getGraphicAnimationFrame(graphic, -1);
2064   }
2065
2066   if (element == EL_EXPANDABLE_WALL)
2067   {
2068     boolean left_stopped = FALSE, right_stopped = FALSE;
2069
2070     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
2071       left_stopped = TRUE;
2072     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
2073       right_stopped = TRUE;
2074
2075     if (left_stopped && right_stopped)
2076       graphic = IMG_WALL;
2077     else if (left_stopped)
2078     {
2079       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
2080       frame = graphic_info[graphic].anim_frames - 1;
2081     }
2082     else if (right_stopped)
2083     {
2084       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
2085       frame = graphic_info[graphic].anim_frames - 1;
2086     }
2087   }
2088
2089   if (dx || dy)
2090     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
2091   else if (mask_mode == USE_MASKING)
2092     DrawGraphicThruMask(x, y, graphic, frame);
2093   else
2094     DrawGraphic(x, y, graphic, frame);
2095 }
2096
2097 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
2098                          int cut_mode, int mask_mode)
2099 {
2100   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2101     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
2102                          cut_mode, mask_mode);
2103 }
2104
2105 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
2106                               int cut_mode)
2107 {
2108   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2109 }
2110
2111 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
2112                              int cut_mode)
2113 {
2114   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
2115 }
2116
2117 void DrawLevelElementThruMask(int x, int y, int element)
2118 {
2119   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2120 }
2121
2122 void DrawLevelFieldThruMask(int x, int y)
2123 {
2124   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2125 }
2126
2127 /* !!! implementation of quicksand is totally broken !!! */
2128 #define IS_CRUMBLED_TILE(x, y, e)                                       \
2129         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
2130                              !IS_MOVING(x, y) ||                        \
2131                              (e) == EL_QUICKSAND_EMPTYING ||            \
2132                              (e) == EL_QUICKSAND_FAST_EMPTYING))
2133
2134 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2135                                                int graphic)
2136 {
2137   Bitmap *src_bitmap;
2138   int src_x, src_y;
2139   int width, height, cx, cy;
2140   int sx = SCREENX(x), sy = SCREENY(y);
2141   int crumbled_border_size = graphic_info[graphic].border_size;
2142   int i;
2143
2144   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2145
2146   for (i = 1; i < 4; i++)
2147   {
2148     int dxx = (i & 1 ? dx : 0);
2149     int dyy = (i & 2 ? dy : 0);
2150     int xx = x + dxx;
2151     int yy = y + dyy;
2152     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2153                    BorderElement);
2154
2155     /* check if neighbour field is of same crumble type */
2156     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2157                     graphic_info[graphic].class ==
2158                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2159
2160     /* return if check prevents inner corner */
2161     if (same == (dxx == dx && dyy == dy))
2162       return;
2163   }
2164
2165   /* if we reach this point, we have an inner corner */
2166
2167   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2168
2169 #if NEW_TILESIZE
2170   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2171   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2172   cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2173   cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2174
2175   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2176              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2177 #else
2178   width  = crumbled_border_size;
2179   height = crumbled_border_size;
2180   cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2181   cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2182
2183   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2184              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2185 #endif
2186 }
2187
2188 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2189                                           int dir)
2190 {
2191   Bitmap *src_bitmap;
2192   int src_x, src_y;
2193   int width, height, bx, by, cx, cy;
2194   int sx = SCREENX(x), sy = SCREENY(y);
2195   int crumbled_border_size = graphic_info[graphic].border_size;
2196   int i;
2197
2198   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2199
2200   /* draw simple, sloppy, non-corner-accurate crumbled border */
2201
2202 #if 1
2203   width  = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2204   height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2205   cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2206   cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2207 #else
2208   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2209   {
2210     width = crumbled_border_size;
2211     height = TILEY;
2212     cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2213     cy = 0;
2214   }
2215   else                                  /* top or bottom crumbled border */
2216   {
2217     width = TILEX;
2218     height = crumbled_border_size;
2219     cx = 0;
2220     cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2221   }
2222 #endif
2223
2224 #if NEW_TILESIZE
2225   BlitBitmap(src_bitmap, drawto_field,
2226              src_x + cx * TILESIZE_VAR / TILESIZE,
2227              src_y + cy * TILESIZE_VAR / TILESIZE,
2228              width * TILESIZE_VAR / TILESIZE,
2229              height * TILESIZE_VAR / TILESIZE,
2230              FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2231              FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2232 #else
2233   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2234              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2235 #endif
2236
2237   /* (remaining middle border part must be at least as big as corner part) */
2238   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2239       crumbled_border_size >= TILESIZE / 3)
2240     return;
2241
2242   /* correct corners of crumbled border, if needed */
2243
2244 #if 1
2245   for (i = -1; i <= 1; i+=2)
2246   {
2247     int xx = x + (dir == 0 || dir == 3 ? i : 0);
2248     int yy = y + (dir == 1 || dir == 2 ? i : 0);
2249     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2250                    BorderElement);
2251
2252     /* check if neighbour field is of same crumble type */
2253     if (IS_CRUMBLED_TILE(xx, yy, element) &&
2254         graphic_info[graphic].class ==
2255         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2256     {
2257       /* no crumbled corner, but continued crumbled border */
2258
2259       int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2260       int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2261       int b1 = (i == 1 ? crumbled_border_size :
2262                 TILESIZE - 2 * crumbled_border_size);
2263
2264       width  = crumbled_border_size;
2265       height = crumbled_border_size;
2266
2267       if (dir == 1 || dir == 2)
2268       {
2269         cx = c1;
2270         cy = c2;
2271         bx = cx;
2272         by = b1;
2273       }
2274       else
2275       {
2276         cx = c2;
2277         cy = c1;
2278         bx = b1;
2279         by = cy;
2280       }
2281
2282 #if NEW_TILESIZE
2283       BlitBitmap(src_bitmap, drawto_field,
2284                  src_x + bx * TILESIZE_VAR / TILESIZE,
2285                  src_y + by * TILESIZE_VAR / TILESIZE,
2286                  width * TILESIZE_VAR / TILESIZE,
2287                  height * TILESIZE_VAR / TILESIZE,
2288                  FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2289                  FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2290 #else
2291       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2292                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2293 #endif
2294     }
2295   }
2296 #else
2297   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2298   {
2299     for (i = -1; i <= 1; i+=2)
2300     {
2301       int xx = x;
2302       int yy = y + i;
2303       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2304                      BorderElement);
2305
2306       /* check if neighbour field is of same crumble type */
2307       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2308           graphic_info[graphic].class ==
2309           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2310       {
2311         /* no crumbled corner, but continued crumbled border */
2312
2313         width  = crumbled_border_size;
2314         height = crumbled_border_size;
2315         cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2316         cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2317         bx = cx;
2318         by = (i == 1 ? crumbled_border_size :
2319               TILEY - 2 * crumbled_border_size);
2320
2321         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2322                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2323       }
2324     }
2325   }
2326   else                          /* top or bottom crumbled border */
2327   {
2328     for (i = -1; i <= 1; i+=2)
2329     {
2330       int xx = x + i;
2331       int yy = y;
2332       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2333                      BorderElement);
2334
2335       /* check if neighbour field is of same crumble type */
2336       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2337           graphic_info[graphic].class ==
2338           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2339       {
2340         /* no crumbled corner, but continued crumbled border */
2341
2342         width  = crumbled_border_size;
2343         height = crumbled_border_size;
2344         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2345         cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2346         bx = (i == 1 ? crumbled_border_size :
2347               TILEX - 2 * crumbled_border_size);
2348         by = cy;
2349
2350         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2351                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2352       }
2353     }
2354   }
2355 #endif
2356 }
2357
2358 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2359 {
2360   int sx = SCREENX(x), sy = SCREENY(y);
2361   int element;
2362   int i;
2363   static int xy[4][2] =
2364   {
2365     { 0, -1 },
2366     { -1, 0 },
2367     { +1, 0 },
2368     { 0, +1 }
2369   };
2370
2371   if (!IN_LEV_FIELD(x, y))
2372     return;
2373
2374   element = TILE_GFX_ELEMENT(x, y);
2375
2376   /* crumble field itself */
2377   if (IS_CRUMBLED_TILE(x, y, element))
2378   {
2379     if (!IN_SCR_FIELD(sx, sy))
2380       return;
2381
2382     for (i = 0; i < 4; i++)
2383     {
2384       int xx = x + xy[i][0];
2385       int yy = y + xy[i][1];
2386
2387       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2388                  BorderElement);
2389
2390       /* check if neighbour field is of same crumble type */
2391 #if 1
2392       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2393           graphic_info[graphic].class ==
2394           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2395         continue;
2396 #else
2397       if (IS_CRUMBLED_TILE(xx, yy, element))
2398         continue;
2399 #endif
2400
2401       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2402     }
2403
2404     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2405         graphic_info[graphic].anim_frames == 2)
2406     {
2407       for (i = 0; i < 4; i++)
2408       {
2409         int dx = (i & 1 ? +1 : -1);
2410         int dy = (i & 2 ? +1 : -1);
2411
2412         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2413       }
2414     }
2415
2416     MarkTileDirty(sx, sy);
2417   }
2418   else          /* center field not crumbled -- crumble neighbour fields */
2419   {
2420     for (i = 0; i < 4; i++)
2421     {
2422       int xx = x + xy[i][0];
2423       int yy = y + xy[i][1];
2424       int sxx = sx + xy[i][0];
2425       int syy = sy + xy[i][1];
2426
2427       if (!IN_LEV_FIELD(xx, yy) ||
2428           !IN_SCR_FIELD(sxx, syy))
2429         continue;
2430
2431       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2432         continue;
2433
2434       element = TILE_GFX_ELEMENT(xx, yy);
2435
2436       if (!IS_CRUMBLED_TILE(xx, yy, element))
2437         continue;
2438
2439       graphic = el_act2crm(element, ACTION_DEFAULT);
2440
2441       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2442
2443       MarkTileDirty(sxx, syy);
2444     }
2445   }
2446 }
2447
2448 void DrawLevelFieldCrumbled(int x, int y)
2449 {
2450   int graphic;
2451
2452   if (!IN_LEV_FIELD(x, y))
2453     return;
2454
2455 #if 1
2456   /* !!! CHECK THIS !!! */
2457
2458   /*
2459   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2460       GFX_CRUMBLED(GfxElement[x][y]))
2461   */
2462
2463   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2464       GfxElement[x][y] != EL_UNDEFINED &&
2465       GFX_CRUMBLED(GfxElement[x][y]))
2466   {
2467     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2468
2469     return;
2470   }
2471 #endif
2472
2473 #if 1
2474   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2475 #else
2476   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2477 #endif
2478
2479   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2480 }
2481
2482 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2483                                    int step_frame)
2484 {
2485   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2486   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2487   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2488   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2489   int sx = SCREENX(x), sy = SCREENY(y);
2490
2491   DrawGraphic(sx, sy, graphic1, frame1);
2492   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2493 }
2494
2495 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2496 {
2497   int sx = SCREENX(x), sy = SCREENY(y);
2498   static int xy[4][2] =
2499   {
2500     { 0, -1 },
2501     { -1, 0 },
2502     { +1, 0 },
2503     { 0, +1 }
2504   };
2505   int i;
2506
2507   for (i = 0; i < 4; i++)
2508   {
2509     int xx = x + xy[i][0];
2510     int yy = y + xy[i][1];
2511     int sxx = sx + xy[i][0];
2512     int syy = sy + xy[i][1];
2513
2514     if (!IN_LEV_FIELD(xx, yy) ||
2515         !IN_SCR_FIELD(sxx, syy) ||
2516         !GFX_CRUMBLED(Feld[xx][yy]) ||
2517         IS_MOVING(xx, yy))
2518       continue;
2519
2520     DrawLevelField(xx, yy);
2521   }
2522 }
2523
2524 static int getBorderElement(int x, int y)
2525 {
2526   int border[7][2] =
2527   {
2528     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
2529     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
2530     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2531     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2532     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
2533     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
2534     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
2535   };
2536   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2537   int steel_position = (x == -1         && y == -1              ? 0 :
2538                         x == lev_fieldx && y == -1              ? 1 :
2539                         x == -1         && y == lev_fieldy      ? 2 :
2540                         x == lev_fieldx && y == lev_fieldy      ? 3 :
2541                         x == -1         || x == lev_fieldx      ? 4 :
2542                         y == -1         || y == lev_fieldy      ? 5 : 6);
2543
2544   return border[steel_position][steel_type];
2545 }
2546
2547 void DrawScreenElement(int x, int y, int element)
2548 {
2549   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2550   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2551 }
2552
2553 void DrawLevelElement(int x, int y, int element)
2554 {
2555   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2556     DrawScreenElement(SCREENX(x), SCREENY(y), element);
2557 }
2558
2559 void DrawScreenField(int x, int y)
2560 {
2561   int lx = LEVELX(x), ly = LEVELY(y);
2562   int element, content;
2563
2564   if (!IN_LEV_FIELD(lx, ly))
2565   {
2566     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2567       element = EL_EMPTY;
2568     else
2569       element = getBorderElement(lx, ly);
2570
2571     DrawScreenElement(x, y, element);
2572
2573     return;
2574   }
2575
2576   element = Feld[lx][ly];
2577   content = Store[lx][ly];
2578
2579   if (IS_MOVING(lx, ly))
2580   {
2581     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2582     boolean cut_mode = NO_CUTTING;
2583
2584     if (element == EL_QUICKSAND_EMPTYING ||
2585         element == EL_QUICKSAND_FAST_EMPTYING ||
2586         element == EL_MAGIC_WALL_EMPTYING ||
2587         element == EL_BD_MAGIC_WALL_EMPTYING ||
2588         element == EL_DC_MAGIC_WALL_EMPTYING ||
2589         element == EL_AMOEBA_DROPPING)
2590       cut_mode = CUT_ABOVE;
2591     else if (element == EL_QUICKSAND_FILLING ||
2592              element == EL_QUICKSAND_FAST_FILLING ||
2593              element == EL_MAGIC_WALL_FILLING ||
2594              element == EL_BD_MAGIC_WALL_FILLING ||
2595              element == EL_DC_MAGIC_WALL_FILLING)
2596       cut_mode = CUT_BELOW;
2597
2598 #if 0
2599     if (lx == 9 && ly == 1)
2600       printf("::: %s [%d] [%d, %d] [%d]\n",
2601              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2602              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2603              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2604              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2605              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2606 #endif
2607
2608     if (cut_mode == CUT_ABOVE)
2609 #if 1
2610       DrawScreenElement(x, y, element);
2611 #else
2612       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2613 #endif
2614     else
2615       DrawScreenElement(x, y, EL_EMPTY);
2616
2617     if (horiz_move)
2618       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2619     else if (cut_mode == NO_CUTTING)
2620       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2621     else
2622     {
2623       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2624
2625 #if 1
2626       if (cut_mode == CUT_BELOW &&
2627           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2628         DrawLevelElement(lx, ly + 1, element);
2629 #endif
2630     }
2631
2632     if (content == EL_ACID)
2633     {
2634       int dir = MovDir[lx][ly];
2635       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2636       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2637
2638       DrawLevelElementThruMask(newlx, newly, EL_ACID);
2639     }
2640   }
2641   else if (IS_BLOCKED(lx, ly))
2642   {
2643     int oldx, oldy;
2644     int sx, sy;
2645     int horiz_move;
2646     boolean cut_mode = NO_CUTTING;
2647     int element_old, content_old;
2648
2649     Blocked2Moving(lx, ly, &oldx, &oldy);
2650     sx = SCREENX(oldx);
2651     sy = SCREENY(oldy);
2652     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2653                   MovDir[oldx][oldy] == MV_RIGHT);
2654
2655     element_old = Feld[oldx][oldy];
2656     content_old = Store[oldx][oldy];
2657
2658     if (element_old == EL_QUICKSAND_EMPTYING ||
2659         element_old == EL_QUICKSAND_FAST_EMPTYING ||
2660         element_old == EL_MAGIC_WALL_EMPTYING ||
2661         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2662         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2663         element_old == EL_AMOEBA_DROPPING)
2664       cut_mode = CUT_ABOVE;
2665
2666     DrawScreenElement(x, y, EL_EMPTY);
2667
2668     if (horiz_move)
2669       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2670                                NO_CUTTING);
2671     else if (cut_mode == NO_CUTTING)
2672       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2673                                cut_mode);
2674     else
2675       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2676                                cut_mode);
2677   }
2678   else if (IS_DRAWABLE(element))
2679     DrawScreenElement(x, y, element);
2680   else
2681     DrawScreenElement(x, y, EL_EMPTY);
2682 }
2683
2684 void DrawLevelField(int x, int y)
2685 {
2686   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2687     DrawScreenField(SCREENX(x), SCREENY(y));
2688   else if (IS_MOVING(x, y))
2689   {
2690     int newx,newy;
2691
2692     Moving2Blocked(x, y, &newx, &newy);
2693     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2694       DrawScreenField(SCREENX(newx), SCREENY(newy));
2695   }
2696   else if (IS_BLOCKED(x, y))
2697   {
2698     int oldx, oldy;
2699
2700     Blocked2Moving(x, y, &oldx, &oldy);
2701     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2702       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2703   }
2704 }
2705
2706 void DrawMiniElement(int x, int y, int element)
2707 {
2708   int graphic;
2709
2710   graphic = el2edimg(element);
2711   DrawMiniGraphic(x, y, graphic);
2712 }
2713
2714 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2715 {
2716   int x = sx + scroll_x, y = sy + scroll_y;
2717
2718   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2719     DrawMiniElement(sx, sy, EL_EMPTY);
2720   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2721     DrawMiniElement(sx, sy, Feld[x][y]);
2722   else
2723     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2724 }
2725
2726 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2727                                  int x, int y, int xsize, int ysize,
2728                                  int tile_width, int tile_height)
2729 {
2730   Bitmap *src_bitmap;
2731   int src_x, src_y;
2732   int dst_x = startx + x * tile_width;
2733   int dst_y = starty + y * tile_height;
2734   int width  = graphic_info[graphic].width;
2735   int height = graphic_info[graphic].height;
2736   int inner_width_raw  = MAX(width  - 2 * tile_width,  tile_width);
2737   int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2738   int inner_width  = inner_width_raw  - (inner_width_raw  % tile_width);
2739   int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2740   int inner_sx = (width  >= 3 * tile_width  ? tile_width  : 0);
2741   int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2742   boolean draw_masked = graphic_info[graphic].draw_masked;
2743
2744   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2745
2746   if (src_bitmap == NULL || width < tile_width || height < tile_height)
2747   {
2748     ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2749     return;
2750   }
2751
2752   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - tile_width  :
2753             inner_sx + (x - 1) * tile_width  % inner_width);
2754   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2755             inner_sy + (y - 1) * tile_height % inner_height);
2756
2757   if (draw_masked)
2758   {
2759     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2760                   dst_x - src_x, dst_y - src_y);
2761     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2762                      dst_x, dst_y);
2763   }
2764   else
2765     BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2766                dst_x, dst_y);
2767 }
2768
2769 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2770                             int x, int y, int xsize, int ysize, int font_nr)
2771 {
2772   int font_width  = getFontWidth(font_nr);
2773   int font_height = getFontHeight(font_nr);
2774
2775   DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2776                               font_width, font_height);
2777 }
2778
2779 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2780 {
2781   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2782   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2783   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2784   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2785   boolean no_delay = (tape.warp_forward);
2786   unsigned int anim_delay = 0;
2787   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2788   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2789   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2790   int font_width = getFontWidth(font_nr);
2791   int font_height = getFontHeight(font_nr);
2792   int max_xsize = level.envelope[envelope_nr].xsize;
2793   int max_ysize = level.envelope[envelope_nr].ysize;
2794   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2795   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2796   int xend = max_xsize;
2797   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2798   int xstep = (xstart < xend ? 1 : 0);
2799   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2800   int x, y;
2801
2802   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2803   {
2804     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2805     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2806     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
2807     int sy = SY + (SYSIZE - ysize * font_height) / 2;
2808     int xx, yy;
2809
2810     SetDrawtoField(DRAW_BUFFERED);
2811
2812 #if 1
2813     BlitScreenToBitmap(backbuffer);
2814 #else
2815     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2816 #endif
2817
2818     SetDrawtoField(DRAW_BACKBUFFER);
2819
2820     for (yy = 0; yy < ysize; yy++)
2821       for (xx = 0; xx < xsize; xx++)
2822         DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2823
2824 #if 1
2825     DrawTextBuffer(sx + font_width, sy + font_height,
2826                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2827                    xsize - 2, ysize - 2, 0, mask_mode,
2828                    level.envelope[envelope_nr].autowrap,
2829                    level.envelope[envelope_nr].centered, FALSE);
2830 #else
2831     DrawTextToTextArea(sx + font_width, sy + font_height,
2832                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2833                        xsize - 2, ysize - 2, mask_mode);
2834 #endif
2835
2836     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2837     BackToFront();
2838
2839     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2840   }
2841 }
2842
2843 void ShowEnvelope(int envelope_nr)
2844 {
2845   int element = EL_ENVELOPE_1 + envelope_nr;
2846   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2847   int sound_opening = element_info[element].sound[ACTION_OPENING];
2848   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2849   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2850   boolean no_delay = (tape.warp_forward);
2851   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2852   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2853   int anim_mode = graphic_info[graphic].anim_mode;
2854   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2855                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2856
2857   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2858
2859   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2860
2861   if (anim_mode == ANIM_DEFAULT)
2862     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2863
2864   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2865
2866   if (tape.playing)
2867     Delay(wait_delay_value);
2868   else
2869     WaitForEventToContinue();
2870
2871   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2872
2873   if (anim_mode != ANIM_NONE)
2874     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2875
2876   if (anim_mode == ANIM_DEFAULT)
2877     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2878
2879   game.envelope_active = FALSE;
2880
2881   SetDrawtoField(DRAW_BUFFERED);
2882
2883   redraw_mask |= REDRAW_FIELD;
2884   BackToFront();
2885 }
2886
2887 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2888 {
2889   int border_size = request.border_size;
2890   int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2891   int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2892   int sx = sx_center - request.width  / 2;
2893   int sy = sy_center - request.height / 2;
2894
2895   if (add_border_size)
2896   {
2897     sx += border_size;
2898     sy += border_size;
2899   }
2900
2901   *x = sx;
2902   *y = sy;
2903 }
2904
2905 void DrawEnvelopeRequest(char *text)
2906 {
2907   char *text_final = text;
2908   char *text_door_style = NULL;
2909   int graphic = IMG_BACKGROUND_REQUEST;
2910   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2911   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2912   int font_nr = FONT_REQUEST;
2913   int font_width = getFontWidth(font_nr);
2914   int font_height = getFontHeight(font_nr);
2915   int border_size = request.border_size;
2916   int line_spacing = request.line_spacing;
2917   int line_height = font_height + line_spacing;
2918   int text_width = request.width - 2 * border_size;
2919   int text_height = request.height - 2 * border_size;
2920   int line_length = text_width / font_width;
2921   int max_lines = text_height / line_height;
2922   int width = request.width;
2923   int height = request.height;
2924   int tile_size = request.step_offset;
2925   int x_steps = width  / tile_size;
2926   int y_steps = height / tile_size;
2927   int sx, sy;
2928   int i, x, y;
2929
2930   if (request.wrap_single_words)
2931   {
2932     char *src_text_ptr, *dst_text_ptr;
2933
2934     text_door_style = checked_malloc(2 * strlen(text) + 1);
2935
2936     src_text_ptr = text;
2937     dst_text_ptr = text_door_style;
2938
2939     while (*src_text_ptr)
2940     {
2941       if (*src_text_ptr == ' ' ||
2942           *src_text_ptr == '?' ||
2943           *src_text_ptr == '!')
2944         *dst_text_ptr++ = '\n';
2945
2946       if (*src_text_ptr != ' ')
2947         *dst_text_ptr++ = *src_text_ptr;
2948
2949       src_text_ptr++;
2950     }
2951
2952     *dst_text_ptr = '\0';
2953
2954     text_final = text_door_style;
2955   }
2956
2957   setRequestPosition(&sx, &sy, FALSE);
2958
2959   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2960
2961   for (y = 0; y < y_steps; y++)
2962     for (x = 0; x < x_steps; x++)
2963       DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2964                                   x, y, x_steps, y_steps,
2965                                   tile_size, tile_size);
2966
2967   DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2968                  line_length, -1, max_lines, line_spacing, mask_mode,
2969                  request.autowrap, request.centered, FALSE);
2970
2971   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2972     RedrawGadget(tool_gadget[i]);
2973
2974   // store readily prepared envelope request for later use when animating
2975   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2976
2977 #if 0
2978   // !!! TEST !!!
2979   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2980   BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2981
2982   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2983   BackToFront();
2984
2985   Delay(3000);
2986
2987   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2988
2989   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2990   BackToFront();
2991
2992   Delay(1000);
2993 #endif
2994
2995   if (text_door_style)
2996     free(text_door_style);
2997 }
2998
2999 #if 1
3000
3001 void AnimateEnvelopeRequest(int anim_mode, int action)
3002 {
3003   int graphic = IMG_BACKGROUND_REQUEST;
3004   boolean draw_masked = graphic_info[graphic].draw_masked;
3005 #if 1
3006   int delay_value_normal = request.step_delay;
3007   int delay_value_fast = delay_value_normal / 2;
3008 #else
3009   int delay_value_normal = GameFrameDelay;
3010   int delay_value_fast = FfwdFrameDelay;
3011 #endif
3012   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3013   boolean no_delay = (tape.warp_forward);
3014   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
3015   int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
3016   unsigned int anim_delay = 0;
3017
3018   int width = request.width;
3019   int height = request.height;
3020   int tile_size = request.step_offset;
3021   int max_xsize = width  / tile_size;
3022   int max_ysize = height / tile_size;
3023   int max_xsize_inner = max_xsize - 2;
3024   int max_ysize_inner = max_ysize - 2;
3025
3026   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
3027   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
3028   int xend = max_xsize_inner;
3029   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
3030   int xstep = (xstart < xend ? 1 : 0);
3031   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3032   int x, y;
3033
3034   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3035   {
3036     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3037     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3038     int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
3039     int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
3040     int src_x = sx_center - width  / 2;
3041     int src_y = sy_center - height / 2;
3042     int dst_x = sx_center - xsize * tile_size / 2;
3043     int dst_y = sy_center - ysize * tile_size / 2;
3044     int xsize_size_left = (xsize - 1) * tile_size;
3045     int ysize_size_top  = (ysize - 1) * tile_size;
3046     int max_xsize_pos = (max_xsize - 1) * tile_size;
3047     int max_ysize_pos = (max_ysize - 1) * tile_size;
3048     int xx, yy;
3049
3050     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3051
3052 #if 1
3053     for (yy = 0; yy < 2; yy++)
3054     {
3055       for (xx = 0; xx < 2; xx++)
3056       {
3057         int src_xx = src_x + xx * max_xsize_pos;
3058         int src_yy = src_y + yy * max_ysize_pos;
3059         int dst_xx = dst_x + xx * xsize_size_left;
3060         int dst_yy = dst_y + yy * ysize_size_top;
3061         int xx_size = (xx ? tile_size : xsize_size_left);
3062         int yy_size = (yy ? tile_size : ysize_size_top);
3063
3064         if (draw_masked)
3065           BlitBitmapMasked(bitmap_db_cross, backbuffer,
3066                            src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3067         else
3068           BlitBitmap(bitmap_db_cross, backbuffer,
3069                      src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
3070       }
3071     }
3072 #else
3073     BlitBitmap(bitmap_db_cross, backbuffer,
3074                src_x, src_y,
3075                xsize_size_left, ysize_size_top,
3076                dst_x, dst_y);
3077     BlitBitmap(bitmap_db_cross, backbuffer,
3078                src_x + max_xsize_pos, src_y,
3079                tile_size, ysize_size_top,
3080                dst_x + xsize_size_left, dst_y);
3081     BlitBitmap(bitmap_db_cross, backbuffer,
3082                src_x, src_y + max_ysize_pos,
3083                xsize_size_left, tile_size,
3084                dst_x, dst_y + ysize_size_top);
3085     BlitBitmap(bitmap_db_cross, backbuffer,
3086                src_x + max_xsize_pos, src_y + max_ysize_pos,
3087                tile_size, tile_size,
3088                dst_x + xsize_size_left, dst_y + ysize_size_top);
3089 #endif
3090
3091 #if 0
3092     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3093     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3094 #else
3095   /* CHECK AGAIN (previous code reactivated) */
3096     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3097 #endif
3098
3099 #if 1
3100     DoAnimation();
3101     BackToFront();
3102 #else
3103     BackToFront();
3104 #endif
3105
3106     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3107   }
3108 }
3109
3110 #else
3111
3112 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
3113 {
3114 #if 0
3115   int envelope_nr = 0;
3116 #endif
3117 #if 1
3118   int graphic = IMG_BACKGROUND_REQUEST;
3119 #else
3120   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3121 #endif
3122   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3123   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3124   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3125   boolean no_delay = (tape.warp_forward);
3126   unsigned int anim_delay = 0;
3127   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3128   int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3129 #if 1
3130   int max_word_len = maxWordLengthInString(text);
3131   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3132 #else
3133   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3134 #endif
3135   int font_width = getFontWidth(font_nr);
3136   int font_height = getFontHeight(font_nr);
3137   int line_spacing = 2 * 1;
3138 #if 1
3139
3140 #if 1
3141   int max_xsize = DXSIZE / font_width;
3142   // int max_ysize = DYSIZE / font_height;
3143   int max_ysize = DYSIZE / (font_height + line_spacing);
3144 #else
3145   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3146   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
3147 #endif
3148
3149 #else
3150   int max_xsize = level.envelope[envelope_nr].xsize;
3151   int max_ysize = level.envelope[envelope_nr].ysize;
3152 #endif
3153   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3154   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3155   int xend = max_xsize;
3156   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3157   int xstep = (xstart < xend ? 1 : 0);
3158   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3159   int x, y;
3160
3161 #if 1
3162   char *text_ptr;
3163   char *text_copy = getStringCopy(text);
3164 #else
3165 #if 1
3166   font_nr = FONT_TEXT_2;
3167
3168   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3169   {
3170     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3171     font_nr = FONT_TEXT_1;
3172   }
3173 #else
3174   int max_word_len = 0;
3175   char *text_ptr;
3176   char *text_copy = getStringCopy(text);
3177
3178   font_nr = FONT_TEXT_2;
3179
3180   for (text_ptr = text; *text_ptr; text_ptr++)
3181   {
3182     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3183
3184     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3185     {
3186       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3187       font_nr = FONT_TEXT_1;
3188
3189       break;
3190     }
3191   }
3192 #endif
3193 #endif
3194
3195 #if 1
3196   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3197     if (*text_ptr == ' ')
3198       *text_ptr = '\n';
3199 #endif
3200
3201 #if 1
3202   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3203   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3204 #else
3205   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
3206   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3207 #endif
3208
3209   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3210   {
3211     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3212     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3213     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
3214     // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3215     int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3216     int xx, yy;
3217
3218 #if 1
3219     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3220 #else
3221     SetDrawtoField(DRAW_BUFFERED);
3222
3223 #if 1
3224     BlitScreenToBitmap(backbuffer);
3225 #else
3226     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3227 #endif
3228
3229     SetDrawtoField(DRAW_BACKBUFFER);
3230 #endif
3231
3232     for (yy = 0; yy < ysize; yy++)
3233       for (xx = 0; xx < xsize; xx++)
3234         DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3235                                     getFontWidth(font_nr),
3236                                     getFontHeight(font_nr) + line_spacing);
3237
3238 #if 1
3239
3240 #if 1
3241     DrawTextBuffer(sx + font_width, sy + font_height + 8,
3242                    text_copy, font_nr, max_xsize,
3243                    xsize - 2, ysize - 2, line_spacing, mask_mode,
3244                    FALSE, TRUE, FALSE);
3245 #else
3246     DrawTextBuffer(sx + font_width, sy + font_height,
3247                    level.envelope[envelope_nr].text, font_nr, max_xsize,
3248                    xsize - 2, ysize - 2, 0, mask_mode,
3249                    level.envelope[envelope_nr].autowrap,
3250                    level.envelope[envelope_nr].centered, FALSE);
3251 #endif
3252
3253 #else
3254     DrawTextToTextArea(sx + font_width, sy + font_height,
3255                        level.envelope[envelope_nr].text, font_nr, max_xsize,
3256                        xsize - 2, ysize - 2, mask_mode);
3257 #endif
3258
3259     /* copy request gadgets to door backbuffer */
3260 #if 1
3261     /*
3262     if ((ysize - 2) > 13)
3263       BlitBitmap(bitmap_db_door, drawto,
3264                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3265                  DOOR_GFX_PAGEY1 + 13 * font_height,
3266                  (xsize - 2) * font_width,
3267                  (ysize - 2 - 13) * font_height,
3268                  sx + font_width,
3269                  sy + font_height * (1 + 13));
3270     */
3271     if ((ysize - 2) > 13)
3272       BlitBitmap(bitmap_db_door, drawto,
3273                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3274                  DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3275                  (xsize - 2) * font_width,
3276                  (ysize - 2 - 13) * (font_height + line_spacing),
3277                  sx + font_width,
3278                  sy + (font_height + line_spacing) * (1 + 13));
3279 #else
3280     if ((ysize - 2) > 13)
3281       BlitBitmap(bitmap_db_door, drawto,
3282                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3283                  DOOR_GFX_PAGEY1 + 13 * font_height,
3284                  (xsize - 2) * font_width,
3285                  (ysize - 2 - 13) * font_height,
3286                  sx + font_width,
3287                  sy + font_height * (1 + 13));
3288 #endif
3289
3290 #if 1
3291     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3292     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3293 #else
3294     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3295 #endif
3296
3297 #if 1
3298     DoAnimation();
3299     BackToFront();
3300 #else
3301     BackToFront();
3302 #endif
3303
3304     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3305   }
3306
3307 #if 1
3308   free(text_copy);
3309 #endif
3310 }
3311
3312 #endif
3313
3314 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3315 {
3316 #if 1
3317   int last_game_status = game_status;   /* save current game status */
3318   // int last_draw_background_mask = gfx.draw_background_mask;
3319 #endif
3320 #if 1
3321   int graphic = IMG_BACKGROUND_REQUEST;
3322   int sound_opening = SND_REQUEST_OPENING;
3323   int sound_closing = SND_REQUEST_CLOSING;
3324 #else
3325   int envelope_nr = 0;
3326   int element = EL_ENVELOPE_1 + envelope_nr;
3327   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3328   int sound_opening = element_info[element].sound[ACTION_OPENING];
3329   int sound_closing = element_info[element].sound[ACTION_CLOSING];
3330 #endif
3331 #if 0
3332   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3333   boolean no_delay = (tape.warp_forward);
3334   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3335   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3336 #endif
3337   int anim_mode = graphic_info[graphic].anim_mode;
3338   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3339                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3340 #if 0
3341   char *text_copy = getStringCopy(text);
3342   char *text_ptr;
3343
3344   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3345     if (*text_ptr == ' ')
3346       *text_ptr = '\n';
3347 #endif
3348
3349 #if 1
3350   if (game_status == GAME_MODE_PLAYING)
3351   {
3352 #if 1
3353 #if 1
3354     BlitScreenToBitmap(backbuffer);
3355 #else
3356     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3357       BlitScreenToBitmap_EM(backbuffer);
3358     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3359       BlitScreenToBitmap_SP(backbuffer);
3360     else
3361       BlitScreenToBitmap_RND(backbuffer);
3362 #endif
3363 #else
3364     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3365       BlitScreenToBitmap_EM(backbuffer);
3366     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3367       BlitScreenToBitmap_SP(backbuffer);
3368     else
3369     {
3370       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3371     }
3372 #endif
3373   }
3374
3375   SetDrawtoField(DRAW_BACKBUFFER);
3376
3377   // SetDrawBackgroundMask(REDRAW_NONE);
3378
3379   if (action == ACTION_OPENING)
3380   {
3381     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3382
3383 #if 1
3384   if (req_state & REQ_ASK)
3385   {
3386     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3387     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3388   }
3389   else if (req_state & REQ_CONFIRM)
3390   {
3391     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3392   }
3393   else if (req_state & REQ_PLAYER)
3394   {
3395     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3396     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3397     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3398     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3399   }
3400 #endif
3401
3402 #if 1
3403     DrawEnvelopeRequest(text);
3404 #else
3405     DrawEnvelopeRequest(text_copy);
3406 #endif
3407
3408     if (game_status != GAME_MODE_MAIN)
3409       InitAnimation();
3410   }
3411
3412   /* force DOOR font inside door area */
3413   game_status = GAME_MODE_PSEUDO_DOOR;
3414 #endif
3415
3416   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
3417
3418   if (action == ACTION_OPENING)
3419   {
3420     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3421
3422     if (anim_mode == ANIM_DEFAULT)
3423       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3424
3425     AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3426
3427 #if 0
3428     if (tape.playing)
3429       Delay(wait_delay_value);
3430     else
3431       WaitForEventToContinue();
3432 #endif
3433   }
3434   else
3435   {
3436     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3437
3438     if (anim_mode != ANIM_NONE)
3439       AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3440
3441     if (anim_mode == ANIM_DEFAULT)
3442       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3443   }
3444
3445   game.envelope_active = FALSE;
3446
3447 #if 1
3448   // game_status = last_game_status;    /* restore current game status */
3449
3450 #if 1
3451   /* !!! CHECK AGAIN (SEE BELOW) !!! */
3452   game_status = last_game_status;       /* restore current game status */
3453 #endif
3454
3455   if (action == ACTION_CLOSING)
3456   {
3457     if (game_status != GAME_MODE_MAIN)
3458       StopAnimation();
3459
3460     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3461   }
3462 #else
3463   SetDrawtoField(DRAW_BUFFERED);
3464 #endif
3465
3466   // SetDrawBackgroundMask(last_draw_background_mask);
3467
3468 #if 0
3469   redraw_mask = REDRAW_FIELD;
3470   // redraw_mask |= REDRAW_ALL;
3471 #else
3472   /* CHECK AGAIN (previous code reactivated) */
3473   redraw_mask |= REDRAW_FIELD;
3474 #endif
3475
3476 #if 1
3477   if (game_status == GAME_MODE_MAIN)
3478     DoAnimation();
3479
3480   BackToFront();
3481
3482 #if 0
3483   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3484   game_status = last_game_status;       /* restore current game status */
3485 #endif
3486
3487 #if 1
3488   if (action == ACTION_CLOSING &&
3489       game_status == GAME_MODE_PLAYING &&
3490       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3491     SetDrawtoField(DRAW_BUFFERED);
3492 #else
3493   if (game_status == GAME_MODE_PLAYING &&
3494       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3495     SetDrawtoField(DRAW_BUFFERED);
3496 #endif
3497
3498 #else
3499   BackToFront();
3500 #endif
3501
3502 #if 0
3503   free(text_copy);
3504 #endif
3505 }
3506
3507 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3508 {
3509   Bitmap *src_bitmap;
3510   int src_x, src_y;
3511   int graphic = el2preimg(element);
3512
3513   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3514   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3515 }
3516
3517 void DrawLevel(int draw_background_mask)
3518 {
3519   int x,y;
3520
3521 #if 1
3522   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3523   SetDrawBackgroundMask(draw_background_mask);
3524 #else
3525 #if 1
3526   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3527   SetDrawBackgroundMask(REDRAW_FIELD);
3528 #else
3529   SetDrawBackgroundMask(REDRAW_NONE);
3530 #endif
3531 #endif
3532
3533   ClearField();
3534
3535   for (x = BX1; x <= BX2; x++)
3536     for (y = BY1; y <= BY2; y++)
3537       DrawScreenField(x, y);
3538
3539   redraw_mask |= REDRAW_FIELD;
3540 }
3541
3542 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3543 {
3544   int x,y;
3545
3546   for (x = 0; x < size_x; x++)
3547     for (y = 0; y < size_y; y++)
3548       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3549
3550   redraw_mask |= REDRAW_FIELD;
3551 }
3552
3553 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3554 {
3555   boolean show_level_border = (BorderElement != EL_EMPTY);
3556   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3557   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3558   int tile_size = preview.tile_size;
3559   int preview_width  = preview.xsize * tile_size;
3560   int preview_height = preview.ysize * tile_size;
3561   int real_preview_xsize = MIN(level_xsize, preview.xsize);
3562   int real_preview_ysize = MIN(level_ysize, preview.ysize);
3563   int real_preview_width  = real_preview_xsize * tile_size;
3564   int real_preview_height = real_preview_ysize * tile_size;
3565   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3566   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3567   int x, y;
3568
3569 #if 1
3570   if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3571     return;
3572 #endif
3573
3574 #if 0
3575   dst_x += (preview_width  - real_preview_width)  / 2;
3576   dst_y += (preview_height - real_preview_height) / 2;
3577
3578   DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3579 #else
3580   DrawBackground(dst_x, dst_y, preview_width, preview_height);
3581
3582   dst_x += (preview_width  - real_preview_width)  / 2;
3583   dst_y += (preview_height - real_preview_height) / 2;
3584 #endif
3585
3586   for (x = 0; x < real_preview_xsize; x++)
3587   {
3588     for (y = 0; y < real_preview_ysize; y++)
3589     {
3590       int lx = from_x + x + (show_level_border ? -1 : 0);
3591       int ly = from_y + y + (show_level_border ? -1 : 0);
3592       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3593                      getBorderElement(lx, ly));
3594
3595       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3596                          element, tile_size);
3597     }
3598   }
3599
3600   redraw_mask |= REDRAW_MICROLEVEL;
3601 }
3602
3603 #define MICROLABEL_EMPTY                0
3604 #define MICROLABEL_LEVEL_NAME           1
3605 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
3606 #define MICROLABEL_LEVEL_AUTHOR         3
3607 #define MICROLABEL_IMPORTED_FROM_HEAD   4
3608 #define MICROLABEL_IMPORTED_FROM        5
3609 #define MICROLABEL_IMPORTED_BY_HEAD     6
3610 #define MICROLABEL_IMPORTED_BY          7
3611
3612 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3613 {
3614   int max_text_width = SXSIZE;
3615   int font_width = getFontWidth(font_nr);
3616
3617   if (pos->align == ALIGN_CENTER)
3618     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3619   else if (pos->align == ALIGN_RIGHT)
3620     max_text_width = pos->x;
3621   else
3622     max_text_width = SXSIZE - pos->x;
3623
3624   return max_text_width / font_width;
3625 }
3626
3627 static void DrawPreviewLevelLabelExt(int mode)
3628 {
3629   struct TextPosInfo *pos = &menu.main.text.level_info_2;
3630   char label_text[MAX_OUTPUT_LINESIZE + 1];
3631   int max_len_label_text;
3632 #if 1
3633   int font_nr = pos->font;
3634   int i;
3635
3636   if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3637     return;
3638
3639   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3640       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3641       mode == MICROLABEL_IMPORTED_BY_HEAD)
3642     font_nr = pos->font_alt;
3643 #else
3644   int font_nr = FONT_TEXT_2;
3645   int i;
3646
3647   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3648       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3649       mode == MICROLABEL_IMPORTED_BY_HEAD)
3650     font_nr = FONT_TEXT_3;
3651 #endif
3652
3653 #if 1
3654   max_len_label_text = getMaxTextLength(pos, font_nr);
3655 #else
3656   max_len_label_text = SXSIZE / getFontWidth(font_nr);
3657 #endif
3658
3659 #if 1
3660   if (pos->size != -1)
3661     max_len_label_text = pos->size;
3662 #endif
3663
3664   for (i = 0; i < max_len_label_text; i++)
3665     label_text[i] = ' ';
3666   label_text[max_len_label_text] = '\0';
3667
3668   if (strlen(label_text) > 0)
3669   {
3670 #if 1
3671     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3672 #else
3673     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3674     int lypos = MICROLABEL2_YPOS;
3675
3676     DrawText(lxpos, lypos, label_text, font_nr);
3677 #endif
3678   }
3679
3680   strncpy(label_text,
3681           (mode == MICROLABEL_LEVEL_NAME ? level.name :
3682            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3683            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3684            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3685            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3686            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3687            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3688           max_len_label_text);
3689   label_text[max_len_label_text] = '\0';
3690
3691   if (strlen(label_text) > 0)
3692   {
3693 #if 1
3694     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3695 #else
3696     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3697     int lypos = MICROLABEL2_YPOS;
3698
3699     DrawText(lxpos, lypos, label_text, font_nr);
3700 #endif
3701   }
3702
3703   redraw_mask |= REDRAW_MICROLEVEL;
3704 }
3705
3706 static void DrawPreviewLevelExt(boolean restart)
3707 {
3708   static unsigned int scroll_delay = 0;
3709   static unsigned int label_delay = 0;
3710   static int from_x, from_y, scroll_direction;
3711   static int label_state, label_counter;
3712   unsigned int scroll_delay_value = preview.step_delay;
3713   boolean show_level_border = (BorderElement != EL_EMPTY);
3714   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3715   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3716   int last_game_status = game_status;           /* save current game status */
3717
3718 #if 0
3719   /* force PREVIEW font on preview level */
3720   game_status = GAME_MODE_PSEUDO_PREVIEW;
3721 #endif
3722
3723   if (restart)
3724   {
3725     from_x = 0;
3726     from_y = 0;
3727
3728     if (preview.anim_mode == ANIM_CENTERED)
3729     {
3730       if (level_xsize > preview.xsize)
3731         from_x = (level_xsize - preview.xsize) / 2;
3732       if (level_ysize > preview.ysize)
3733         from_y = (level_ysize - preview.ysize) / 2;
3734     }
3735
3736     from_x += preview.xoffset;
3737     from_y += preview.yoffset;
3738
3739     scroll_direction = MV_RIGHT;
3740     label_state = 1;
3741     label_counter = 0;
3742
3743     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3744     DrawPreviewLevelLabelExt(label_state);
3745
3746     /* initialize delay counters */
3747     DelayReached(&scroll_delay, 0);
3748     DelayReached(&label_delay, 0);
3749
3750     if (leveldir_current->name)
3751     {
3752       struct TextPosInfo *pos = &menu.main.text.level_info_1;
3753       char label_text[MAX_OUTPUT_LINESIZE + 1];
3754 #if 1
3755       int font_nr = pos->font;
3756 #else
3757       int font_nr = FONT_TEXT_1;
3758 #endif
3759 #if 1
3760       int max_len_label_text = getMaxTextLength(pos, font_nr);
3761 #else
3762       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3763 #endif
3764 #if 0
3765       int text_width;
3766       int lxpos, lypos;
3767 #endif
3768
3769 #if 1
3770       if (pos->size != -1)
3771         max_len_label_text = pos->size;
3772 #endif
3773
3774       strncpy(label_text, leveldir_current->name, max_len_label_text);
3775       label_text[max_len_label_text] = '\0';
3776
3777 #if 1
3778       if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3779         DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3780 #else
3781       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3782       lypos = SY + MICROLABEL1_YPOS;
3783
3784       DrawText(lxpos, lypos, label_text, font_nr);
3785 #endif
3786     }
3787
3788     game_status = last_game_status;     /* restore current game status */
3789
3790     return;
3791   }
3792
3793   /* scroll preview level, if needed */
3794   if (preview.anim_mode != ANIM_NONE &&
3795       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3796       DelayReached(&scroll_delay, scroll_delay_value))
3797   {
3798     switch (scroll_direction)
3799     {
3800       case MV_LEFT:
3801         if (from_x > 0)
3802         {
3803           from_x -= preview.step_offset;
3804           from_x = (from_x < 0 ? 0 : from_x);
3805         }
3806         else
3807           scroll_direction = MV_UP;
3808         break;
3809
3810       case MV_RIGHT:
3811         if (from_x < level_xsize - preview.xsize)
3812         {
3813           from_x += preview.step_offset;
3814           from_x = (from_x > level_xsize - preview.xsize ?
3815                     level_xsize - preview.xsize : from_x);
3816         }
3817         else
3818           scroll_direction = MV_DOWN;
3819         break;
3820
3821       case MV_UP:
3822         if (from_y > 0)
3823         {
3824           from_y -= preview.step_offset;
3825           from_y = (from_y < 0 ? 0 : from_y);
3826         }
3827         else
3828           scroll_direction = MV_RIGHT;
3829         break;
3830
3831       case MV_DOWN:
3832         if (from_y < level_ysize - preview.ysize)
3833         {
3834           from_y += preview.step_offset;
3835           from_y = (from_y > level_ysize - preview.ysize ?
3836                     level_ysize - preview.ysize : from_y);
3837         }
3838         else
3839           scroll_direction = MV_LEFT;
3840         break;
3841
3842       default:
3843         break;
3844     }
3845
3846     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3847   }
3848
3849   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3850   /* redraw micro level label, if needed */
3851   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3852       !strEqual(level.author, ANONYMOUS_NAME) &&
3853       !strEqual(level.author, leveldir_current->name) &&
3854       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3855   {
3856     int max_label_counter = 23;
3857
3858     if (leveldir_current->imported_from != NULL &&
3859         strlen(leveldir_current->imported_from) > 0)
3860       max_label_counter += 14;
3861     if (leveldir_current->imported_by != NULL &&
3862         strlen(leveldir_current->imported_by) > 0)
3863       max_label_counter += 14;
3864
3865     label_counter = (label_counter + 1) % max_label_counter;
3866     label_state = (label_counter >= 0 && label_counter <= 7 ?
3867                    MICROLABEL_LEVEL_NAME :
3868                    label_counter >= 9 && label_counter <= 12 ?
3869                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3870                    label_counter >= 14 && label_counter <= 21 ?
3871                    MICROLABEL_LEVEL_AUTHOR :
3872                    label_counter >= 23 && label_counter <= 26 ?
3873                    MICROLABEL_IMPORTED_FROM_HEAD :
3874                    label_counter >= 28 && label_counter <= 35 ?
3875                    MICROLABEL_IMPORTED_FROM :
3876                    label_counter >= 37 && label_counter <= 40 ?
3877                    MICROLABEL_IMPORTED_BY_HEAD :
3878                    label_counter >= 42 && label_counter <= 49 ?
3879                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3880
3881     if (leveldir_current->imported_from == NULL &&
3882         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3883          label_state == MICROLABEL_IMPORTED_FROM))
3884       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3885                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3886
3887     DrawPreviewLevelLabelExt(label_state);
3888   }
3889
3890   game_status = last_game_status;       /* restore current game status */
3891 }
3892
3893 void DrawPreviewLevelInitial()
3894 {
3895   DrawPreviewLevelExt(TRUE);
3896 }
3897
3898 void DrawPreviewLevelAnimation()
3899 {
3900   DrawPreviewLevelExt(FALSE);
3901 }
3902
3903 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3904                                     int graphic, int sync_frame, int mask_mode)
3905 {
3906   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3907
3908   if (mask_mode == USE_MASKING)
3909     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3910   else
3911     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3912 }
3913
3914 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3915                                          int graphic, int sync_frame,
3916                                          int mask_mode)
3917 {
3918   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3919
3920   if (mask_mode == USE_MASKING)
3921     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3922   else
3923     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3924 }
3925
3926 inline void DrawGraphicAnimation(int x, int y, int graphic)
3927 {
3928   int lx = LEVELX(x), ly = LEVELY(y);
3929
3930   if (!IN_SCR_FIELD(x, y))
3931     return;
3932
3933 #if NEW_TILESIZE
3934   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3935                           graphic, GfxFrame[lx][ly], NO_MASKING);
3936 #else
3937   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3938                           graphic, GfxFrame[lx][ly], NO_MASKING);
3939 #endif
3940   MarkTileDirty(x, y);
3941 }
3942
3943 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3944 {
3945   int lx = LEVELX(x), ly = LEVELY(y);
3946
3947   if (!IN_SCR_FIELD(x, y))
3948     return;
3949
3950   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3951                           graphic, GfxFrame[lx][ly], NO_MASKING);
3952   MarkTileDirty(x, y);
3953 }
3954
3955 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3956 {
3957   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3958 }
3959
3960 void DrawLevelElementAnimation(int x, int y, int element)
3961 {
3962   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3963
3964   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3965 }
3966
3967 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3968 {
3969   int sx = SCREENX(x), sy = SCREENY(y);
3970
3971   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3972     return;
3973
3974   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3975     return;
3976
3977   DrawGraphicAnimation(sx, sy, graphic);
3978
3979 #if 1
3980   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3981     DrawLevelFieldCrumbled(x, y);
3982 #else
3983   if (GFX_CRUMBLED(Feld[x][y]))
3984     DrawLevelFieldCrumbled(x, y);
3985 #endif
3986 }
3987
3988 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3989 {
3990   int sx = SCREENX(x), sy = SCREENY(y);
3991   int graphic;
3992
3993   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3994     return;
3995
3996   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3997
3998   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3999     return;
4000
4001   DrawGraphicAnimation(sx, sy, graphic);
4002
4003   if (GFX_CRUMBLED(element))
4004     DrawLevelFieldCrumbled(x, y);
4005 }
4006
4007 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
4008 {
4009   if (player->use_murphy)
4010   {
4011     /* this works only because currently only one player can be "murphy" ... */
4012     static int last_horizontal_dir = MV_LEFT;
4013     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
4014
4015     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4016       last_horizontal_dir = move_dir;
4017
4018     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
4019     {
4020       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
4021
4022       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
4023     }
4024
4025     return graphic;
4026   }
4027   else
4028     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
4029 }
4030
4031 static boolean equalGraphics(int graphic1, int graphic2)
4032 {
4033   struct GraphicInfo *g1 = &graphic_info[graphic1];
4034   struct GraphicInfo *g2 = &graphic_info[graphic2];
4035
4036   return (g1->bitmap      == g2->bitmap &&
4037           g1->src_x       == g2->src_x &&
4038           g1->src_y       == g2->src_y &&
4039           g1->anim_frames == g2->anim_frames &&
4040           g1->anim_delay  == g2->anim_delay &&
4041           g1->anim_mode   == g2->anim_mode);
4042 }
4043
4044 void DrawAllPlayers()
4045 {
4046   int i;
4047
4048   for (i = 0; i < MAX_PLAYERS; i++)
4049     if (stored_player[i].active)
4050       DrawPlayer(&stored_player[i]);
4051 }
4052
4053 void DrawPlayerField(int x, int y)
4054 {
4055   if (!IS_PLAYER(x, y))
4056     return;
4057
4058   DrawPlayer(PLAYERINFO(x, y));
4059 }
4060
4061 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
4062
4063 void DrawPlayer(struct PlayerInfo *player)
4064 {
4065   int jx = player->jx;
4066   int jy = player->jy;
4067   int move_dir = player->MovDir;
4068   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
4069   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
4070   int last_jx = (player->is_moving ? jx - dx : jx);
4071   int last_jy = (player->is_moving ? jy - dy : jy);
4072   int next_jx = jx + dx;
4073   int next_jy = jy + dy;
4074   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
4075   boolean player_is_opaque = FALSE;
4076   int sx = SCREENX(jx), sy = SCREENY(jy);
4077   int sxx = 0, syy = 0;
4078   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
4079   int graphic;
4080   int action = ACTION_DEFAULT;
4081   int last_player_graphic = getPlayerGraphic(player, move_dir);
4082   int last_player_frame = player->Frame;
4083   int frame = 0;
4084
4085   /* GfxElement[][] is set to the element the player is digging or collecting;
4086      remove also for off-screen player if the player is not moving anymore */
4087   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
4088     GfxElement[jx][jy] = EL_UNDEFINED;
4089
4090   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
4091     return;
4092
4093 #if DEBUG
4094   if (!IN_LEV_FIELD(jx, jy))
4095   {
4096     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
4097     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
4098     printf("DrawPlayerField(): This should never happen!\n");
4099     return;
4100   }
4101 #endif
4102
4103   if (element == EL_EXPLOSION)
4104     return;
4105
4106   action = (player->is_pushing    ? ACTION_PUSHING         :
4107             player->is_digging    ? ACTION_DIGGING         :
4108             player->is_collecting ? ACTION_COLLECTING      :
4109             player->is_moving     ? ACTION_MOVING          :
4110             player->is_snapping   ? ACTION_SNAPPING        :
4111             player->is_dropping   ? ACTION_DROPPING        :
4112             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
4113
4114   if (player->is_waiting)
4115     move_dir = player->dir_waiting;
4116
4117   InitPlayerGfxAnimation(player, action, move_dir);
4118
4119   /* ----------------------------------------------------------------------- */
4120   /* draw things in the field the player is leaving, if needed               */
4121   /* ----------------------------------------------------------------------- */
4122
4123   if (player->is_moving)
4124   {
4125     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
4126     {
4127       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
4128
4129       if (last_element == EL_DYNAMITE_ACTIVE ||
4130           last_element == EL_EM_DYNAMITE_ACTIVE ||
4131           last_element == EL_SP_DISK_RED_ACTIVE)
4132         DrawDynamite(last_jx, last_jy);
4133       else
4134         DrawLevelFieldThruMask(last_jx, last_jy);
4135     }
4136     else if (last_element == EL_DYNAMITE_ACTIVE ||
4137              last_element == EL_EM_DYNAMITE_ACTIVE ||
4138              last_element == EL_SP_DISK_RED_ACTIVE)
4139       DrawDynamite(last_jx, last_jy);
4140 #if 0
4141     /* !!! this is not enough to prevent flickering of players which are
4142        moving next to each others without a free tile between them -- this
4143        can only be solved by drawing all players layer by layer (first the
4144        background, then the foreground etc.) !!! => TODO */
4145     else if (!IS_PLAYER(last_jx, last_jy))
4146       DrawLevelField(last_jx, last_jy);
4147 #else
4148     else
4149       DrawLevelField(last_jx, last_jy);
4150 #endif
4151
4152     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4153       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4154   }
4155
4156   if (!IN_SCR_FIELD(sx, sy))
4157     return;
4158
4159   /* ----------------------------------------------------------------------- */
4160   /* draw things behind the player, if needed                                */
4161   /* ----------------------------------------------------------------------- */
4162
4163   if (Back[jx][jy])
4164     DrawLevelElement(jx, jy, Back[jx][jy]);
4165   else if (IS_ACTIVE_BOMB(element))
4166     DrawLevelElement(jx, jy, EL_EMPTY);
4167   else
4168   {
4169     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4170     {
4171       int old_element = GfxElement[jx][jy];
4172       int old_graphic = el_act_dir2img(old_element, action, move_dir);
4173       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4174
4175       if (GFX_CRUMBLED(old_element))
4176         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4177       else
4178         DrawGraphic(sx, sy, old_graphic, frame);
4179
4180       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4181         player_is_opaque = TRUE;
4182     }
4183     else
4184     {
4185       GfxElement[jx][jy] = EL_UNDEFINED;
4186
4187       /* make sure that pushed elements are drawn with correct frame rate */
4188 #if 1
4189       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4190
4191       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4192         GfxFrame[jx][jy] = player->StepFrame;
4193 #else
4194       if (player->is_pushing && player->is_moving)
4195         GfxFrame[jx][jy] = player->StepFrame;
4196 #endif
4197
4198       DrawLevelField(jx, jy);
4199     }
4200   }
4201
4202 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4203   /* ----------------------------------------------------------------------- */
4204   /* draw player himself                                                     */
4205   /* ----------------------------------------------------------------------- */
4206
4207   graphic = getPlayerGraphic(player, move_dir);
4208
4209   /* in the case of changed player action or direction, prevent the current
4210      animation frame from being restarted for identical animations */
4211   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4212     player->Frame = last_player_frame;
4213
4214   frame = getGraphicAnimationFrame(graphic, player->Frame);
4215
4216   if (player->GfxPos)
4217   {
4218     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4219       sxx = player->GfxPos;
4220     else
4221       syy = player->GfxPos;
4222   }
4223
4224   if (!setup.soft_scrolling && ScreenMovPos)
4225     sxx = syy = 0;
4226
4227   if (player_is_opaque)
4228     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4229   else
4230     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4231
4232   if (SHIELD_ON(player))
4233   {
4234     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4235                    IMG_SHIELD_NORMAL_ACTIVE);
4236     int frame = getGraphicAnimationFrame(graphic, -1);
4237
4238     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4239   }
4240 #endif
4241
4242 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4243   if (player->GfxPos)
4244   {
4245     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4246       sxx = player->GfxPos;
4247     else
4248       syy = player->GfxPos;
4249   }
4250 #endif
4251
4252   /* ----------------------------------------------------------------------- */
4253   /* draw things the player is pushing, if needed                            */
4254   /* ----------------------------------------------------------------------- */
4255
4256 #if 0
4257   printf("::: %d, %d [%d, %d] [%d]\n",
4258          player->is_pushing, player_is_moving, player->GfxAction,
4259          player->is_moving, player_is_moving);
4260 #endif
4261
4262 #if 1
4263   if (player->is_pushing && player->is_moving)
4264   {
4265     int px = SCREENX(jx), py = SCREENY(jy);
4266     int pxx = (TILEX - ABS(sxx)) * dx;
4267     int pyy = (TILEY - ABS(syy)) * dy;
4268     int gfx_frame = GfxFrame[jx][jy];
4269
4270     int graphic;
4271     int sync_frame;
4272     int frame;
4273
4274     if (!IS_MOVING(jx, jy))             /* push movement already finished */
4275     {
4276       element = Feld[next_jx][next_jy];
4277       gfx_frame = GfxFrame[next_jx][next_jy];
4278     }
4279
4280     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4281
4282 #if 1
4283     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4284     frame = getGraphicAnimationFrame(graphic, sync_frame);
4285 #else
4286     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4287 #endif
4288
4289     /* draw background element under pushed element (like the Sokoban field) */
4290 #if 1
4291     if (game.use_masked_pushing && IS_MOVING(jx, jy))
4292     {
4293       /* this allows transparent pushing animation over non-black background */
4294
4295       if (Back[jx][jy])
4296         DrawLevelElement(jx, jy, Back[jx][jy]);
4297       else
4298         DrawLevelElement(jx, jy, EL_EMPTY);
4299
4300       if (Back[next_jx][next_jy])
4301         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4302       else
4303         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4304     }
4305     else if (Back[next_jx][next_jy])
4306       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4307 #else
4308     if (Back[next_jx][next_jy])
4309       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4310 #endif
4311
4312 #if 0
4313     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4314            jx, px, player->GfxPos, player->StepFrame,
4315            player->is_pushing,
4316            dx, sxx, pxx,
4317            IS_MOVING(jx, jy),
4318            graphic, frame,
4319            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4320 #endif
4321
4322 #if 1
4323     /* do not draw (EM style) pushing animation when pushing is finished */
4324     /* (two-tile animations usually do not contain start and end frame) */
4325     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4326       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4327     else
4328       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4329 #else
4330     /* masked drawing is needed for EMC style (double) movement graphics */
4331     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4332     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4333 #endif
4334   }
4335 #endif
4336
4337 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4338   /* ----------------------------------------------------------------------- */
4339   /* draw player himself                                                     */
4340   /* ----------------------------------------------------------------------- */
4341
4342   graphic = getPlayerGraphic(player, move_dir);
4343
4344   /* in the case of changed player action or direction, prevent the current
4345      animation frame from being restarted for identical animations */
4346   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4347     player->Frame = last_player_frame;
4348
4349   frame = getGraphicAnimationFrame(graphic, player->Frame);
4350
4351   if (player->GfxPos)
4352   {
4353     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4354       sxx = player->GfxPos;
4355     else
4356       syy = player->GfxPos;
4357   }
4358
4359   if (!setup.soft_scrolling && ScreenMovPos)
4360     sxx = syy = 0;
4361
4362   if (player_is_opaque)
4363     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4364   else
4365     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4366
4367   if (SHIELD_ON(player))
4368   {
4369     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4370                    IMG_SHIELD_NORMAL_ACTIVE);
4371     int frame = getGraphicAnimationFrame(graphic, -1);
4372
4373     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4374   }
4375 #endif
4376
4377   /* ----------------------------------------------------------------------- */
4378   /* draw things in front of player (active dynamite or dynabombs)           */
4379   /* ----------------------------------------------------------------------- */
4380
4381   if (IS_ACTIVE_BOMB(element))
4382   {
4383     graphic = el2img(element);
4384     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4385
4386     if (game.emulation == EMU_SUPAPLEX)
4387       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4388     else
4389       DrawGraphicThruMask(sx, sy, graphic, frame);
4390   }
4391
4392   if (player_is_moving && last_element == EL_EXPLOSION)
4393   {
4394     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4395                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
4396     int graphic = el_act2img(element, ACTION_EXPLODING);
4397     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4398     int phase = ExplodePhase[last_jx][last_jy] - 1;
4399     int frame = getGraphicAnimationFrame(graphic, phase - delay);
4400
4401     if (phase >= delay)
4402       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4403   }
4404
4405   /* ----------------------------------------------------------------------- */
4406   /* draw elements the player is just walking/passing through/under          */
4407   /* ----------------------------------------------------------------------- */
4408
4409   if (player_is_moving)
4410   {
4411     /* handle the field the player is leaving ... */
4412     if (IS_ACCESSIBLE_INSIDE(last_element))
4413       DrawLevelField(last_jx, last_jy);
4414     else if (IS_ACCESSIBLE_UNDER(last_element))
4415       DrawLevelFieldThruMask(last_jx, last_jy);
4416   }
4417
4418   /* do not redraw accessible elements if the player is just pushing them */
4419   if (!player_is_moving || !player->is_pushing)
4420   {
4421     /* ... and the field the player is entering */
4422     if (IS_ACCESSIBLE_INSIDE(element))
4423       DrawLevelField(jx, jy);
4424     else if (IS_ACCESSIBLE_UNDER(element))
4425       DrawLevelFieldThruMask(jx, jy);
4426   }
4427
4428   MarkTileDirty(sx, sy);
4429 }
4430
4431 /* ------------------------------------------------------------------------- */
4432
4433 void WaitForEventToContinue()
4434 {
4435   boolean still_wait = TRUE;
4436
4437   /* simulate releasing mouse button over last gadget, if still pressed */
4438   if (button_status)
4439     HandleGadgets(-1, -1, 0);
4440
4441   button_status = MB_RELEASED;
4442
4443 #if 1
4444   ClearEventQueue();
4445 #endif
4446
4447   while (still_wait)
4448   {
4449     if (PendingEvent())
4450     {
4451       Event event;
4452
4453       NextEvent(&event);
4454
4455       switch (event.type)
4456       {
4457         case EVENT_BUTTONPRESS:
4458         case EVENT_KEYPRESS:
4459           still_wait = FALSE;
4460           break;
4461
4462         case EVENT_KEYRELEASE:
4463           ClearPlayerAction();
4464           break;
4465
4466         default:
4467           HandleOtherEvents(&event);
4468           break;
4469       }
4470     }
4471     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4472     {
4473       still_wait = FALSE;
4474     }
4475
4476     DoAnimation();
4477
4478     /* don't eat all CPU time */
4479     Delay(10);
4480   }
4481 }
4482
4483 #define MAX_REQUEST_LINES               13
4484 #define MAX_REQUEST_LINE_FONT1_LEN      7
4485 #define MAX_REQUEST_LINE_FONT2_LEN      10
4486
4487 #if 1
4488
4489 static int RequestHandleEvents(unsigned int req_state)
4490 {
4491   int last_game_status = game_status;   /* save current game status */
4492   int result;
4493   int mx, my;
4494
4495   button_status = MB_RELEASED;
4496
4497   request_gadget_id = -1;
4498   result = -1;
4499
4500   while (result < 0)
4501   {
4502     if (PendingEvent())
4503     {
4504       Event event;
4505
4506       NextEvent(&event);
4507
4508       switch (event.type)
4509       {
4510         case EVENT_BUTTONPRESS:
4511         case EVENT_BUTTONRELEASE:
4512         case EVENT_MOTIONNOTIFY:
4513         {
4514           if (event.type == EVENT_MOTIONNOTIFY)
4515           {
4516             if (!PointerInWindow(window))
4517               continue; /* window and pointer are on different screens */
4518
4519             if (!button_status)
4520               continue;
4521
4522             motion_status = TRUE;
4523             mx = ((MotionEvent *) &event)->x;
4524             my = ((MotionEvent *) &event)->y;
4525           }
4526           else
4527           {
4528             motion_status = FALSE;
4529             mx = ((ButtonEvent *) &event)->x;
4530             my = ((ButtonEvent *) &event)->y;
4531             if (event.type == EVENT_BUTTONPRESS)
4532               button_status = ((ButtonEvent *) &event)->button;
4533             else
4534               button_status = MB_RELEASED;
4535           }
4536
4537           /* this sets 'request_gadget_id' */
4538           HandleGadgets(mx, my, button_status);
4539
4540           switch (request_gadget_id)
4541           {
4542             case TOOL_CTRL_ID_YES:
4543               result = TRUE;
4544               break;
4545             case TOOL_CTRL_ID_NO:
4546               result = FALSE;
4547               break;
4548             case TOOL_CTRL_ID_CONFIRM:
4549               result = TRUE | FALSE;
4550               break;
4551
4552             case TOOL_CTRL_ID_PLAYER_1:
4553               result = 1;
4554               break;
4555             case TOOL_CTRL_ID_PLAYER_2:
4556               result = 2;
4557               break;
4558             case TOOL_CTRL_ID_PLAYER_3:
4559               result = 3;
4560               break;
4561             case TOOL_CTRL_ID_PLAYER_4:
4562               result = 4;
4563               break;
4564
4565             default:
4566               break;
4567           }
4568
4569           break;
4570         }
4571
4572         case EVENT_KEYPRESS:
4573           switch (GetEventKey((KeyEvent *)&event, TRUE))
4574           {
4575             case KSYM_space:
4576               if (req_state & REQ_CONFIRM)
4577                 result = 1;
4578               break;
4579
4580             case KSYM_Return:
4581               result = 1;
4582               break;
4583
4584             case KSYM_Escape:
4585 #if defined(TARGET_SDL2)
4586             case KSYM_Back:
4587 #endif
4588               result = 0;
4589               break;
4590
4591             default:
4592               break;
4593           }
4594
4595           if (req_state & REQ_PLAYER)
4596             result = 0;
4597           break;
4598
4599         case EVENT_KEYRELEASE:
4600           ClearPlayerAction();
4601           break;
4602
4603         default:
4604           HandleOtherEvents(&event);
4605           break;
4606       }
4607     }
4608     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4609     {
4610       int joy = AnyJoystick();
4611
4612       if (joy & JOY_BUTTON_1)
4613         result = 1;
4614       else if (joy & JOY_BUTTON_2)
4615         result = 0;
4616     }
4617
4618 #if 1
4619
4620     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4621     {
4622       HandleGameActions();
4623     }
4624     else
4625     {
4626       DoAnimation();
4627
4628       if (!PendingEvent())      /* delay only if no pending events */
4629         Delay(10);
4630     }
4631
4632 #if 1
4633     game_status = GAME_MODE_PSEUDO_DOOR;
4634 #endif
4635
4636     BackToFront();
4637
4638 #if 1
4639     game_status = last_game_status;     /* restore current game status */
4640 #endif
4641
4642 #else
4643
4644     DoAnimation();
4645
4646 #if 1
4647     if (!PendingEvent())        /* delay only if no pending events */
4648       Delay(10);
4649 #else
4650     /* don't eat all CPU time */
4651     Delay(10);
4652 #endif
4653
4654 #endif
4655   }
4656
4657   return result;
4658 }
4659
4660 static boolean RequestDoor(char *text, unsigned int req_state)
4661 {
4662   unsigned int old_door_state;
4663   int last_game_status = game_status;   /* save current game status */
4664   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4665   int font_nr = FONT_TEXT_2;
4666   char *text_ptr;
4667   int result;
4668   int ty;
4669
4670   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4671   {
4672     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4673     font_nr = FONT_TEXT_1;
4674   }
4675
4676   if (game_status == GAME_MODE_PLAYING)
4677   {
4678 #if 1
4679     BlitScreenToBitmap(backbuffer);
4680 #else
4681     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4682       BlitScreenToBitmap_EM(backbuffer);
4683     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4684       BlitScreenToBitmap_SP(backbuffer);
4685 #endif
4686   }
4687
4688   /* disable deactivated drawing when quick-loading level tape recording */
4689   if (tape.playing && tape.deactivate_display)
4690     TapeDeactivateDisplayOff(TRUE);
4691
4692   SetMouseCursor(CURSOR_DEFAULT);
4693
4694 #if defined(NETWORK_AVALIABLE)
4695   /* pause network game while waiting for request to answer */
4696   if (options.network &&
4697       game_status == GAME_MODE_PLAYING &&
4698       req_state & REQUEST_WAIT_FOR_INPUT)
4699     SendToServer_PausePlaying();
4700 #endif
4701
4702   old_door_state = GetDoorState();
4703
4704   /* simulate releasing mouse button over last gadget, if still pressed */
4705   if (button_status)
4706     HandleGadgets(-1, -1, 0);
4707
4708   UnmapAllGadgets();
4709
4710   /* draw released gadget before proceeding */
4711   // BackToFront();
4712
4713   if (old_door_state & DOOR_OPEN_1)
4714   {
4715     CloseDoor(DOOR_CLOSE_1);
4716
4717     /* save old door content */
4718 #if 1
4719     BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4720                0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4721 #else
4722     BlitBitmap(bitmap_db_door, bitmap_db_door,
4723                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4724                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4725 #endif
4726   }
4727
4728   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4729   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4730
4731   /* clear door drawing field */
4732   DrawBackground(DX, DY, DXSIZE, DYSIZE);
4733
4734   /* force DOOR font inside door area */
4735   game_status = GAME_MODE_PSEUDO_DOOR;
4736
4737   /* write text for request */
4738   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4739   {
4740     char text_line[max_request_line_len + 1];
4741     int tx, tl, tc = 0;
4742
4743     if (!*text_ptr)
4744       break;
4745
4746     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4747     {
4748       tc = *(text_ptr + tx);
4749       // if (!tc || tc == ' ')
4750       if (!tc || tc == ' ' || tc == '?' || tc == '!')
4751         break;
4752     }
4753
4754     if ((tc == '?' || tc == '!') && tl == 0)
4755       tl = 1;
4756
4757     if (!tl)
4758     { 
4759       text_ptr++; 
4760       ty--; 
4761       continue; 
4762     }
4763
4764     strncpy(text_line, text_ptr, tl);
4765     text_line[tl] = 0;
4766
4767     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4768              DY + 8 + ty * (getFontHeight(font_nr) + 2),
4769              text_line, font_nr);
4770
4771     text_ptr += tl + (tc == ' ' ? 1 : 0);
4772     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4773   }
4774
4775   game_status = last_game_status;       /* restore current game status */
4776
4777   if (req_state & REQ_ASK)
4778   {
4779     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4780     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4781   }
4782   else if (req_state & REQ_CONFIRM)
4783   {
4784     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4785   }
4786   else if (req_state & REQ_PLAYER)
4787   {
4788     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4789     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4790     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4791     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4792   }
4793
4794   /* copy request gadgets to door backbuffer */
4795 #if 1
4796   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4797 #else
4798   BlitBitmap(drawto, bitmap_db_door,
4799              DX, DY, DXSIZE, DYSIZE,
4800              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4801 #endif
4802
4803   OpenDoor(DOOR_OPEN_1);
4804
4805   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4806   {
4807     if (game_status == GAME_MODE_PLAYING)
4808     {
4809       SetPanelBackground();
4810       SetDrawBackgroundMask(REDRAW_DOOR_1);
4811     }
4812     else
4813     {
4814       SetDrawBackgroundMask(REDRAW_FIELD);
4815     }
4816
4817     return FALSE;
4818   }
4819
4820   if (game_status != GAME_MODE_MAIN)
4821     InitAnimation();
4822
4823   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4824
4825   // ---------- handle request buttons ----------
4826   result = RequestHandleEvents(req_state);
4827
4828   if (game_status != GAME_MODE_MAIN)
4829     StopAnimation();
4830
4831   UnmapToolButtons();
4832
4833   if (!(req_state & REQ_STAY_OPEN))
4834   {
4835     CloseDoor(DOOR_CLOSE_1);
4836
4837     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4838         (req_state & REQ_REOPEN))
4839       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4840   }
4841
4842   RemapAllGadgets();
4843
4844   if (game_status == GAME_MODE_PLAYING)
4845   {
4846     SetPanelBackground();
4847     SetDrawBackgroundMask(REDRAW_DOOR_1);
4848   }
4849   else
4850   {
4851     SetDrawBackgroundMask(REDRAW_FIELD);
4852   }
4853
4854 #if defined(NETWORK_AVALIABLE)
4855   /* continue network game after request */
4856   if (options.network &&
4857       game_status == GAME_MODE_PLAYING &&
4858       req_state & REQUEST_WAIT_FOR_INPUT)
4859     SendToServer_ContinuePlaying();
4860 #endif
4861
4862   /* restore deactivated drawing when quick-loading level tape recording */
4863   if (tape.playing && tape.deactivate_display)
4864     TapeDeactivateDisplayOn();
4865
4866   return result;
4867 }
4868
4869 static boolean RequestEnvelope(char *text, unsigned int req_state)
4870 {
4871   int result;
4872 #if 0
4873   int i;
4874 #endif
4875
4876   if (game_status == GAME_MODE_PLAYING)
4877   {
4878 #if 1
4879 #if 1
4880     BlitScreenToBitmap(backbuffer);
4881 #else
4882     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4883       BlitScreenToBitmap_EM(backbuffer);
4884     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4885       BlitScreenToBitmap_SP(backbuffer);
4886     else
4887       BlitScreenToBitmap_RND(backbuffer);
4888 #endif
4889 #else
4890     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4891       BlitScreenToBitmap_EM(backbuffer);
4892     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4893       BlitScreenToBitmap_SP(backbuffer);
4894 #endif
4895   }
4896
4897   /* disable deactivated drawing when quick-loading level tape recording */
4898   if (tape.playing && tape.deactivate_display)
4899     TapeDeactivateDisplayOff(TRUE);
4900
4901   SetMouseCursor(CURSOR_DEFAULT);
4902
4903 #if defined(NETWORK_AVALIABLE)
4904   /* pause network game while waiting for request to answer */
4905   if (options.network &&
4906       game_status == GAME_MODE_PLAYING &&
4907       req_state & REQUEST_WAIT_FOR_INPUT)
4908     SendToServer_PausePlaying();
4909 #endif
4910
4911   /* simulate releasing mouse button over last gadget, if still pressed */
4912   if (button_status)
4913     HandleGadgets(-1, -1, 0);
4914
4915   UnmapAllGadgets();
4916
4917   // (replace with setting corresponding request background)
4918   // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4919   // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4920
4921   /* clear door drawing field */
4922   // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4923
4924 #if 0
4925   if (global.use_envelope_request)
4926   {
4927     /* !!! TMP !!! */
4928     FreeToolButtons();
4929     CreateToolButtons();
4930   }
4931 #endif
4932
4933 #if 0
4934 #if 0
4935   if (req_state & REQ_ASK)
4936   {
4937     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4938     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4939   }
4940   else if (req_state & REQ_CONFIRM)
4941   {
4942     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4943   }
4944   else if (req_state & REQ_PLAYER)
4945   {
4946     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4947     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4948     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4949     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4950   }
4951 #else
4952   if (req_state & REQ_ASK)
4953   {
4954     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4955     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4956   }
4957   else if (req_state & REQ_CONFIRM)
4958   {
4959     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4960   }
4961   else if (req_state & REQ_PLAYER)
4962   {
4963     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4964     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4965     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4966     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4967   }
4968 #endif
4969 #endif
4970
4971   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4972
4973 #if 0
4974   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4975   {
4976     if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4977                                  i == TOOL_CTRL_ID_NO)) ||
4978         (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4979         (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4980                                     i == TOOL_CTRL_ID_PLAYER_2 &&
4981                                     i == TOOL_CTRL_ID_PLAYER_3 &&
4982                                     i == TOOL_CTRL_ID_PLAYER_4)))
4983     {
4984       int x = tool_gadget[i]->x + dDX;
4985       int y = tool_gadget[i]->y + dDY;
4986
4987       ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4988     }
4989   }
4990 #endif
4991
4992   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4993   {
4994     if (game_status == GAME_MODE_PLAYING)
4995     {
4996       SetPanelBackground();
4997       SetDrawBackgroundMask(REDRAW_DOOR_1);
4998     }
4999     else
5000     {
5001       SetDrawBackgroundMask(REDRAW_FIELD);
5002     }
5003
5004     return FALSE;
5005   }
5006
5007 #if 0
5008   if (game_status != GAME_MODE_MAIN)
5009     InitAnimation();
5010 #endif
5011
5012   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5013
5014   // ---------- handle request buttons ----------
5015   result = RequestHandleEvents(req_state);
5016
5017   if (game_status != GAME_MODE_MAIN)
5018     StopAnimation();
5019
5020   UnmapToolButtons();
5021
5022   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5023
5024   RemapAllGadgets();
5025
5026   if (game_status == GAME_MODE_PLAYING)
5027   {
5028     SetPanelBackground();
5029     SetDrawBackgroundMask(REDRAW_DOOR_1);
5030   }
5031   else
5032   {
5033     SetDrawBackgroundMask(REDRAW_FIELD);
5034   }
5035
5036 #if defined(NETWORK_AVALIABLE)
5037   /* continue network game after request */
5038   if (options.network &&
5039       game_status == GAME_MODE_PLAYING &&
5040       req_state & REQUEST_WAIT_FOR_INPUT)
5041     SendToServer_ContinuePlaying();
5042 #endif
5043
5044   /* restore deactivated drawing when quick-loading level tape recording */
5045   if (tape.playing && tape.deactivate_display)
5046     TapeDeactivateDisplayOn();
5047
5048   return result;
5049 }
5050
5051 boolean Request(char *text, unsigned int req_state)
5052 {
5053   if (global.use_envelope_request)
5054     return RequestEnvelope(text, req_state);
5055   else
5056     return RequestDoor(text, req_state);
5057 }
5058
5059 #else   // =====================================================================
5060
5061 boolean Request(char *text, unsigned int req_state)
5062 {
5063   int mx, my, ty, result = -1;
5064   unsigned int old_door_state;
5065   int last_game_status = game_status;   /* save current game status */
5066   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5067   int font_nr = FONT_TEXT_2;
5068 #if 0
5069   int max_word_len = 0;
5070 #endif
5071   char *text_ptr;
5072   int i;
5073
5074 #if 0
5075   global.use_envelope_request = 1;
5076 #endif
5077
5078 #if 1
5079   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5080   {
5081     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5082     font_nr = FONT_TEXT_1;
5083   }
5084 #else
5085   for (text_ptr = text; *text_ptr; text_ptr++)
5086   {
5087     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5088
5089     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5090     {
5091       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5092 #if 1
5093       font_nr = FONT_TEXT_1;
5094 #else
5095       font_nr = FONT_LEVEL_NUMBER;
5096 #endif
5097
5098       break;
5099     }
5100   }
5101 #endif
5102
5103   if (game_status == GAME_MODE_PLAYING)
5104   {
5105 #if 1
5106     BlitScreenToBitmap(backbuffer);
5107 #else
5108     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5109       BlitScreenToBitmap_EM(backbuffer);
5110     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5111       BlitScreenToBitmap_SP(backbuffer);
5112 #endif
5113   }
5114
5115   /* disable deactivated drawing when quick-loading level tape recording */
5116   if (tape.playing && tape.deactivate_display)
5117     TapeDeactivateDisplayOff(TRUE);
5118
5119   SetMouseCursor(CURSOR_DEFAULT);
5120
5121 #if defined(NETWORK_AVALIABLE)
5122   /* pause network game while waiting for request to answer */
5123   if (options.network &&
5124       game_status == GAME_MODE_PLAYING &&
5125       req_state & REQUEST_WAIT_FOR_INPUT)
5126     SendToServer_PausePlaying();
5127 #endif
5128
5129   old_door_state = GetDoorState();
5130
5131   /* simulate releasing mouse button over last gadget, if still pressed */
5132   if (button_status)
5133     HandleGadgets(-1, -1, 0);
5134
5135   UnmapAllGadgets();
5136
5137   /* draw released gadget before proceeding */
5138   // BackToFront();
5139
5140 #if 0
5141   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5142 #else
5143   if (old_door_state & DOOR_OPEN_1)
5144 #endif
5145   {
5146 #if 1
5147     if (!global.use_envelope_request)
5148       CloseDoor(DOOR_CLOSE_1);
5149 #else
5150     CloseDoor(DOOR_CLOSE_1);
5151 #endif
5152
5153     /* save old door content */
5154     BlitBitmap(bitmap_db_door, bitmap_db_door,
5155                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5156                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5157   }
5158
5159 #if 1
5160   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5161 #endif
5162
5163   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5164
5165   /* clear door drawing field */
5166   DrawBackground(DX, DY, DXSIZE, DYSIZE);
5167
5168   /* force DOOR font inside door area */
5169   game_status = GAME_MODE_PSEUDO_DOOR;
5170
5171   /* write text for request */
5172   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5173   {
5174     char text_line[max_request_line_len + 1];
5175     int tx, tl, tc = 0;
5176
5177     if (!*text_ptr)
5178       break;
5179
5180     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5181     {
5182       tc = *(text_ptr + tx);
5183       if (!tc || tc == ' ')
5184         break;
5185     }
5186
5187     if (!tl)
5188     { 
5189       text_ptr++; 
5190       ty--; 
5191       continue; 
5192     }
5193
5194     strncpy(text_line, text_ptr, tl);
5195     text_line[tl] = 0;
5196
5197     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5198              DY + 8 + ty * (getFontHeight(font_nr) + 2),
5199              text_line, font_nr);
5200
5201     text_ptr += tl + (tc == ' ' ? 1 : 0);
5202   }
5203
5204   game_status = last_game_status;       /* restore current game status */
5205
5206 #if 1
5207   if (global.use_envelope_request)
5208   {
5209     /* !!! TMP !!! */
5210     FreeToolButtons();
5211     CreateToolButtons();
5212   }
5213 #endif
5214
5215   if (req_state & REQ_ASK)
5216   {
5217     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5218     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5219   }
5220   else if (req_state & REQ_CONFIRM)
5221   {
5222     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5223   }
5224   else if (req_state & REQ_PLAYER)
5225   {
5226     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5227     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5228     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5229     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5230   }
5231
5232   /* copy request gadgets to door backbuffer */
5233   BlitBitmap(drawto, bitmap_db_door,
5234              DX, DY, DXSIZE, DYSIZE,
5235              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5236
5237 #if 1
5238   if (global.use_envelope_request)
5239   {
5240     ShowEnvelopeRequest(text, ACTION_OPENING);
5241
5242     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5243     {
5244       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5245                                    i == TOOL_CTRL_ID_NO)) ||
5246           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5247           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5248                                       i == TOOL_CTRL_ID_PLAYER_2 &&
5249                                       i == TOOL_CTRL_ID_PLAYER_3 &&
5250                                       i == TOOL_CTRL_ID_PLAYER_4)))
5251       {
5252         int x = tool_gadget[i]->x + dDX;
5253         int y = tool_gadget[i]->y + dDY;
5254
5255         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5256       }
5257     }
5258   }
5259 #endif
5260
5261 #if 1
5262   if (!global.use_envelope_request)
5263     OpenDoor(DOOR_OPEN_1);
5264 #else
5265   OpenDoor(DOOR_OPEN_1);
5266 #endif
5267
5268   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5269   {
5270     if (game_status == GAME_MODE_PLAYING)
5271     {
5272       SetPanelBackground();
5273       SetDrawBackgroundMask(REDRAW_DOOR_1);
5274     }
5275     else
5276     {
5277       SetDrawBackgroundMask(REDRAW_FIELD);
5278     }
5279
5280     return FALSE;
5281   }
5282
5283 #if 1
5284   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5285     InitAnimation();
5286 #else
5287   if (game_status != GAME_MODE_MAIN)
5288     InitAnimation();
5289 #endif
5290
5291   button_status = MB_RELEASED;
5292
5293   request_gadget_id = -1;
5294
5295   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5296
5297   while (result < 0)
5298   {
5299     if (PendingEvent())
5300     {
5301       Event event;
5302
5303       NextEvent(&event);
5304
5305       switch (event.type)
5306       {
5307         case EVENT_BUTTONPRESS:
5308         case EVENT_BUTTONRELEASE:
5309         case EVENT_MOTIONNOTIFY:
5310         {
5311           if (event.type == EVENT_MOTIONNOTIFY)
5312           {
5313             if (!PointerInWindow(window))
5314               continue; /* window and pointer are on different screens */
5315
5316             if (!button_status)
5317               continue;
5318
5319             motion_status = TRUE;
5320             mx = ((MotionEvent *) &event)->x;
5321             my = ((MotionEvent *) &event)->y;
5322           }
5323           else
5324           {
5325             motion_status = FALSE;
5326             mx = ((ButtonEvent *) &event)->x;
5327             my = ((ButtonEvent *) &event)->y;
5328             if (event.type == EVENT_BUTTONPRESS)
5329               button_status = ((ButtonEvent *) &event)->button;
5330             else
5331               button_status = MB_RELEASED;
5332           }
5333
5334           /* this sets 'request_gadget_id' */
5335           HandleGadgets(mx, my, button_status);
5336
5337           switch (request_gadget_id)
5338           {
5339             case TOOL_CTRL_ID_YES:
5340               result = TRUE;
5341               break;
5342             case TOOL_CTRL_ID_NO:
5343               result = FALSE;
5344               break;
5345             case TOOL_CTRL_ID_CONFIRM:
5346               result = TRUE | FALSE;
5347               break;
5348
5349             case TOOL_CTRL_ID_PLAYER_1:
5350               result = 1;
5351               break;
5352             case TOOL_CTRL_ID_PLAYER_2:
5353               result = 2;
5354               break;
5355             case TOOL_CTRL_ID_PLAYER_3:
5356               result = 3;
5357               break;
5358             case TOOL_CTRL_ID_PLAYER_4:
5359               result = 4;
5360               break;
5361
5362             default:
5363               break;
5364           }
5365
5366           break;
5367         }
5368
5369         case EVENT_KEYPRESS:
5370           switch (GetEventKey((KeyEvent *)&event, TRUE))
5371           {
5372             case KSYM_space:
5373               if (req_state & REQ_CONFIRM)
5374                 result = 1;
5375               break;
5376
5377             case KSYM_Return:
5378               result = 1;
5379               break;
5380
5381             case KSYM_Escape:
5382 #if defined(TARGET_SDL2)
5383             case KSYM_Back:
5384 #endif
5385               result = 0;
5386               break;
5387
5388             default:
5389               break;
5390           }
5391
5392           if (req_state & REQ_PLAYER)
5393             result = 0;
5394           break;
5395
5396         case EVENT_KEYRELEASE:
5397           ClearPlayerAction();
5398           break;
5399
5400         default:
5401           HandleOtherEvents(&event);
5402           break;
5403       }
5404     }
5405     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5406     {
5407       int joy = AnyJoystick();
5408
5409       if (joy & JOY_BUTTON_1)
5410         result = 1;
5411       else if (joy & JOY_BUTTON_2)
5412         result = 0;
5413     }
5414
5415 #if 1
5416
5417     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5418     {
5419       HandleGameActions();
5420     }
5421     else
5422     {
5423       DoAnimation();
5424
5425       if (!PendingEvent())      /* delay only if no pending events */
5426         Delay(10);
5427     }
5428
5429 #if 1
5430     game_status = GAME_MODE_PSEUDO_DOOR;
5431 #endif
5432
5433     BackToFront();
5434
5435 #if 1
5436     game_status = last_game_status;     /* restore current game status */
5437 #endif
5438
5439 #else
5440
5441     DoAnimation();
5442
5443 #if 1
5444     if (!PendingEvent())        /* delay only if no pending events */
5445       Delay(10);
5446 #else
5447     /* don't eat all CPU time */
5448     Delay(10);
5449 #endif
5450
5451 #endif
5452   }
5453
5454   if (game_status != GAME_MODE_MAIN)
5455     StopAnimation();
5456
5457   UnmapToolButtons();
5458
5459 #if 1
5460   if (global.use_envelope_request)
5461     ShowEnvelopeRequest(text, ACTION_CLOSING);
5462 #endif
5463
5464 #if 1
5465   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5466 #else
5467   if (!(req_state & REQ_STAY_OPEN))
5468 #endif
5469   {
5470     CloseDoor(DOOR_CLOSE_1);
5471
5472     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5473         (req_state & REQ_REOPEN))
5474       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5475   }
5476
5477   RemapAllGadgets();
5478
5479   if (game_status == GAME_MODE_PLAYING)
5480   {
5481     SetPanelBackground();
5482     SetDrawBackgroundMask(REDRAW_DOOR_1);
5483   }
5484   else
5485   {
5486     SetDrawBackgroundMask(REDRAW_FIELD);
5487   }
5488
5489 #if defined(NETWORK_AVALIABLE)
5490   /* continue network game after request */
5491   if (options.network &&
5492       game_status == GAME_MODE_PLAYING &&
5493       req_state & REQUEST_WAIT_FOR_INPUT)
5494     SendToServer_ContinuePlaying();
5495 #endif
5496
5497   /* restore deactivated drawing when quick-loading level tape recording */
5498   if (tape.playing && tape.deactivate_display)
5499     TapeDeactivateDisplayOn();
5500
5501   return result;
5502 }
5503
5504 #endif
5505
5506 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5507 {
5508   const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5509   const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5510   int compare_result;
5511
5512   if (dpo1->sort_priority != dpo2->sort_priority)
5513     compare_result = dpo1->sort_priority - dpo2->sort_priority;
5514   else
5515     compare_result = dpo1->nr - dpo2->nr;
5516
5517   return compare_result;
5518 }
5519
5520 void InitGraphicCompatibilityInfo_Doors()
5521 {
5522   struct
5523   {
5524     int door_token;
5525     int part_1, part_8;
5526     struct DoorInfo *door;
5527   }
5528   doors[] =
5529   {
5530     { DOOR_1,   IMG_DOOR_1_GFX_PART_1,  IMG_DOOR_1_GFX_PART_8,  &door_1 },
5531     { DOOR_2,   IMG_DOOR_2_GFX_PART_1,  IMG_DOOR_2_GFX_PART_8,  &door_2 },
5532
5533     { -1,       -1,                     -1,                     NULL    }
5534   };
5535   struct Rect door_rect_list[] =
5536   {
5537     { DX, DY, DXSIZE, DYSIZE },
5538     { VX, VY, VXSIZE, VYSIZE }
5539   };
5540   int i, j;
5541
5542   for (i = 0; doors[i].door_token != -1; i++)
5543   {
5544     int door_token = doors[i].door_token;
5545     int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5546     int part_1 = doors[i].part_1;
5547     int part_8 = doors[i].part_8;
5548     int part_2 = part_1 + 1;
5549     int part_3 = part_1 + 2;
5550     struct DoorInfo *door = doors[i].door;
5551     struct Rect *door_rect = &door_rect_list[door_index];
5552     boolean door_gfx_redefined = FALSE;
5553
5554     /* check if any door part graphic definitions have been redefined */
5555
5556     for (j = 0; door_part_controls[j].door_token != -1; j++)
5557     {
5558       struct DoorPartControlInfo *dpc = &door_part_controls[j];
5559       struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5560
5561       if (dpc->door_token == door_token && fi->redefined)
5562         door_gfx_redefined = TRUE;
5563     }
5564
5565     /* check for old-style door graphic/animation modifications */
5566
5567     if (!door_gfx_redefined)
5568     {
5569       if (door->anim_mode & ANIM_STATIC_PANEL)
5570       {
5571         door->panel.step_xoffset = 0;
5572         door->panel.step_yoffset = 0;
5573       }
5574
5575       if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5576       {
5577         struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5578         struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5579         int num_door_steps, num_panel_steps;
5580
5581         /* remove door part graphics other than the two default wings */
5582
5583         for (j = 0; door_part_controls[j].door_token != -1; j++)
5584         {
5585           struct DoorPartControlInfo *dpc = &door_part_controls[j];
5586           struct GraphicInfo *g = &graphic_info[dpc->graphic];
5587
5588           if (dpc->graphic >= part_3 &&
5589               dpc->graphic <= part_8)
5590             g->bitmap = NULL;
5591         }
5592
5593         /* set graphics and screen positions of the default wings */
5594
5595         g_part_1->width  = door_rect->width;
5596         g_part_1->height = door_rect->height;
5597         g_part_2->width  = door_rect->width;
5598         g_part_2->height = door_rect->height;
5599         g_part_2->src_x = door_rect->width;
5600         g_part_2->src_y = g_part_1->src_y;
5601
5602         door->part_2.x = door->part_1.x;
5603         door->part_2.y = door->part_1.y;
5604
5605         if (door->width != -1)
5606         {
5607           g_part_1->width = door->width;
5608           g_part_2->width = door->width;
5609
5610           // special treatment for graphics and screen position of right wing
5611           g_part_2->src_x += door_rect->width - door->width;
5612           door->part_2.x  += door_rect->width - door->width;
5613         }
5614
5615         if (door->height != -1)
5616         {
5617           g_part_1->height = door->height;
5618           g_part_2->height = door->height;
5619
5620           // special treatment for graphics and screen position of bottom wing
5621           g_part_2->src_y += door_rect->height - door->height;
5622           door->part_2.y  += door_rect->height - door->height;
5623         }
5624
5625         /* set animation delays for the default wings and panels */
5626
5627         door->part_1.step_delay = door->step_delay;
5628         door->part_2.step_delay = door->step_delay;
5629         door->panel.step_delay  = door->step_delay;
5630
5631         /* set animation draw order for the default wings */
5632
5633         door->part_1.sort_priority = 2; /* draw left wing over ... */
5634         door->part_2.sort_priority = 1; /*          ... right wing */
5635
5636         /* set animation draw offset for the default wings */
5637
5638         if (door->anim_mode & ANIM_HORIZONTAL)
5639         {
5640           door->part_1.step_xoffset = door->step_offset;
5641           door->part_1.step_yoffset = 0;
5642           door->part_2.step_xoffset = door->step_offset * -1;
5643           door->part_2.step_yoffset = 0;
5644
5645           num_door_steps = g_part_1->width / door->step_offset;
5646         }
5647         else    // ANIM_VERTICAL
5648         {
5649           door->part_1.step_xoffset = 0;
5650           door->part_1.step_yoffset = door->step_offset;
5651           door->part_2.step_xoffset = 0;
5652           door->part_2.step_yoffset = door->step_offset * -1;
5653
5654           num_door_steps = g_part_1->height / door->step_offset;
5655         }
5656
5657         /* set animation draw offset for the default panels */
5658
5659         if (door->step_offset > 1)
5660         {
5661           num_panel_steps = 2 * door_rect->height / door->step_offset;
5662           door->panel.start_step = num_panel_steps - num_door_steps;
5663         }
5664         else
5665         {
5666           num_panel_steps = door_rect->height / door->step_offset;
5667           door->panel.start_step = num_panel_steps - num_door_steps / 2;
5668           door->panel.step_delay *= 2;
5669         }
5670       }
5671     }
5672   }
5673 }
5674
5675 void InitDoors()
5676 {
5677   int i;
5678
5679   for (i = 0; door_part_controls[i].door_token != -1; i++)
5680   {
5681     struct DoorPartControlInfo *dpc = &door_part_controls[i];
5682     struct DoorPartOrderInfo *dpo = &door_part_order[i];
5683
5684     /* initialize "start_step_opening" and "start_step_closing", if needed */
5685     if (dpc->pos->start_step_opening == 0 &&
5686         dpc->pos->start_step_closing == 0)
5687     {
5688       // dpc->pos->start_step_opening = dpc->pos->start_step;
5689       dpc->pos->start_step_closing = dpc->pos->start_step;
5690     }
5691
5692     /* fill structure for door part draw order (sorted below) */
5693     dpo->nr = i;
5694     dpo->sort_priority = dpc->pos->sort_priority;
5695
5696 #if 0
5697     struct DoorPartPosInfo *pos = dpc->pos;
5698
5699     printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5700            pos->step_xoffset, pos->step_yoffset);
5701 #endif
5702   }
5703
5704   /* sort door part controls according to sort_priority and graphic number */
5705   qsort(door_part_order, MAX_DOOR_PARTS,
5706         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5707 }
5708
5709 unsigned int OpenDoor(unsigned int door_state)
5710 {
5711   if (door_state & DOOR_COPY_BACK)
5712   {
5713 #if 1
5714     if (door_state & DOOR_OPEN_1)
5715       BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5716                  1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5717
5718     if (door_state & DOOR_OPEN_2)
5719       BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5720                  1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5721 #else
5722     if (door_state & DOOR_OPEN_1)
5723       BlitBitmap(bitmap_db_door, bitmap_db_door,
5724                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5725                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5726
5727     if (door_state & DOOR_OPEN_2)
5728       BlitBitmap(bitmap_db_door, bitmap_db_door,
5729                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5730                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5731 #endif
5732
5733     door_state &= ~DOOR_COPY_BACK;
5734   }
5735
5736   return MoveDoor(door_state);
5737 }
5738
5739 unsigned int CloseDoor(unsigned int door_state)
5740 {
5741   unsigned int old_door_state = GetDoorState();
5742
5743   if (!(door_state & DOOR_NO_COPY_BACK))
5744   {
5745 #if 1
5746     if (old_door_state & DOOR_OPEN_1)
5747       BlitBitmap(backbuffer, bitmap_db_door_1,
5748                  DX, DY, DXSIZE, DYSIZE, 0, 0);
5749
5750     if (old_door_state & DOOR_OPEN_2)
5751       BlitBitmap(backbuffer, bitmap_db_door_2,
5752                  VX, VY, VXSIZE, VYSIZE, 0, 0);
5753 #else
5754     if (old_door_state & DOOR_OPEN_1)
5755       BlitBitmap(backbuffer, bitmap_db_door,
5756                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5757
5758     if (old_door_state & DOOR_OPEN_2)
5759       BlitBitmap(backbuffer, bitmap_db_door,
5760                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5761 #endif
5762
5763     door_state &= ~DOOR_NO_COPY_BACK;
5764   }
5765
5766   return MoveDoor(door_state);
5767 }
5768
5769 unsigned int GetDoorState()
5770 {
5771   return MoveDoor(DOOR_GET_STATE);
5772 }
5773
5774 unsigned int SetDoorState(unsigned int door_state)
5775 {
5776   return MoveDoor(door_state | DOOR_SET_STATE);
5777 }
5778
5779 #if 1
5780
5781 // ========== TEST 1 ===========================================================
5782
5783 int euclid(int a, int b)
5784 {
5785   return (b ? euclid(b, a % b) : a);
5786 }
5787
5788 unsigned int MoveDoor(unsigned int door_state)
5789 {
5790 #if 0
5791   struct XY panel_pos_list[] =
5792   {
5793     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5794     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5795   };
5796 #endif
5797   struct Rect door_rect_list[] =
5798   {
5799     { DX, DY, DXSIZE, DYSIZE },
5800     { VX, VY, VXSIZE, VYSIZE }
5801   };
5802   static int door1 = DOOR_OPEN_1;
5803   static int door2 = DOOR_CLOSE_2;
5804   unsigned int door_delay = 0;
5805   unsigned int door_delay_value;
5806   int i;
5807
5808 #if 1
5809   if (door_1.width < 0 || door_1.width > DXSIZE)
5810     door_1.width = DXSIZE;
5811   if (door_1.height < 0 || door_1.height > DYSIZE)
5812     door_1.height = DYSIZE;
5813   if (door_2.width < 0 || door_2.width > VXSIZE)
5814     door_2.width = VXSIZE;
5815   if (door_2.height < 0 || door_2.height > VYSIZE)
5816     door_2.height = VYSIZE;
5817 #endif
5818
5819   if (door_state == DOOR_GET_STATE)
5820     return (door1 | door2);
5821
5822   if (door_state & DOOR_SET_STATE)
5823   {
5824     if (door_state & DOOR_ACTION_1)
5825       door1 = door_state & DOOR_ACTION_1;
5826     if (door_state & DOOR_ACTION_2)
5827       door2 = door_state & DOOR_ACTION_2;
5828
5829     return (door1 | door2);
5830   }
5831
5832   if (!(door_state & DOOR_FORCE_REDRAW))
5833   {
5834     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5835       door_state &= ~DOOR_OPEN_1;
5836     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5837       door_state &= ~DOOR_CLOSE_1;
5838     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5839       door_state &= ~DOOR_OPEN_2;
5840     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5841       door_state &= ~DOOR_CLOSE_2;
5842   }
5843
5844 #if 0
5845   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5846                       door_2.step_delay);
5847
5848   if (setup.quick_doors)
5849   {
5850     stepsize = 20;              /* must be chosen to always draw last frame */
5851     door_delay_value = 0;
5852   }
5853 #endif
5854
5855   if (global.autoplay_leveldir)
5856   {
5857     door_state |= DOOR_NO_DELAY;
5858     door_state &= ~DOOR_CLOSE_ALL;
5859   }
5860
5861 #if 1
5862   if (game_status == GAME_MODE_EDITOR)
5863     door_state |= DOOR_NO_DELAY;
5864 #endif
5865
5866   if (door_state & DOOR_ACTION)
5867   {
5868     boolean door_panel_drawn[NUM_DOORS];
5869     boolean panel_has_doors[NUM_DOORS];
5870     boolean door_part_skip[MAX_DOOR_PARTS];
5871     boolean door_part_done[MAX_DOOR_PARTS];
5872     boolean door_part_done_all;
5873     int num_steps[MAX_DOOR_PARTS];
5874     int max_move_delay = 0;     // delay for complete animations of all doors
5875     int max_step_delay = 0;     // delay (ms) between two animation frames
5876     int num_move_steps = 0;     // number of animation steps for all doors
5877     int current_move_delay = 0;
5878     int k;
5879
5880     for (i = 0; i < NUM_DOORS; i++)
5881       panel_has_doors[i] = FALSE;
5882
5883     for (i = 0; i < MAX_DOOR_PARTS; i++)
5884     {
5885       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5886       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5887       int door_token = dpc->door_token;
5888
5889       door_part_done[i] = FALSE;
5890       door_part_skip[i] = (!(door_state & door_token) ||
5891                            !g->bitmap);
5892     }
5893
5894 #if 0
5895     for (i = 0; i < MAX_DOOR_PARTS; i++)
5896     {
5897       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5898       struct DoorPartPosInfo *pos = dpc->pos;
5899       int start_step = pos->start_step;
5900
5901       printf("::: ---> %d: start_step == %d [%d]\n",
5902              i, start_step, door_part_done[i]);
5903     }
5904 #endif
5905
5906     for (i = 0; i < MAX_DOOR_PARTS; i++)
5907     {
5908       int nr = door_part_order[i].nr;
5909       struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5910       struct DoorPartPosInfo *pos = dpc->pos;
5911       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5912       int door_token = dpc->door_token;
5913       int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5914       boolean is_panel = DOOR_PART_IS_PANEL(nr);
5915       int step_xoffset = ABS(pos->step_xoffset);
5916       int step_yoffset = ABS(pos->step_yoffset);
5917       int step_delay = pos->step_delay;
5918       int current_door_state = door_state & door_token;
5919       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5920       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5921       boolean part_opening = (is_panel ? door_closing : door_opening);
5922       int start_step = (part_opening ? pos->start_step_opening :
5923                         pos->start_step_closing);
5924       float move_xsize = (step_xoffset ? g->width  : 0);
5925       float move_ysize = (step_yoffset ? g->height : 0);
5926       int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5927       int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5928       int move_steps = (move_xsteps && move_ysteps ?
5929                         MIN(move_xsteps, move_ysteps) :
5930                         move_xsteps ? move_xsteps : move_ysteps) - start_step;
5931       int move_delay = move_steps * step_delay;
5932
5933       if (door_part_skip[nr])
5934         continue;
5935
5936       if (!is_panel)
5937         panel_has_doors[door_index] = TRUE;
5938
5939       max_move_delay = MAX(max_move_delay, move_delay);
5940       max_step_delay = (max_step_delay == 0 ? step_delay :
5941                         euclid(max_step_delay, step_delay));
5942       num_steps[nr] = move_steps;
5943
5944 #if 0
5945 #if 0
5946       printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5947              i, move_delay, start_step, door_part_order[i].nr);
5948 #else
5949       if (DOOR_PART_IS_PANEL(i))
5950         printf("::: %d: move_delay == %d, start_step == %d\n",
5951                i, move_delay, start_step);
5952 #endif
5953 #endif
5954     }
5955
5956     num_move_steps = max_move_delay / max_step_delay;
5957
5958     door_delay_value = max_step_delay;
5959
5960 #if 0
5961     door_delay_value *= 10;
5962 #endif
5963
5964 #if 0
5965     printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5966 #endif
5967
5968     for (k = 0; k < num_move_steps; k++)
5969     {
5970       door_part_done_all = TRUE;
5971
5972       for (i = 0; i < NUM_DOORS; i++)
5973         door_panel_drawn[i] = FALSE;
5974
5975       for (i = 0; i < MAX_DOOR_PARTS; i++)
5976       {
5977         int nr = door_part_order[i].nr;
5978         struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5979         struct DoorPartPosInfo *pos = dpc->pos;
5980         struct GraphicInfo *g = &graphic_info[dpc->graphic];
5981         int door_token = dpc->door_token;
5982         int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5983         boolean is_panel = DOOR_PART_IS_PANEL(nr);
5984 #if 0
5985         struct XY *panel_pos = &panel_pos_list[door_index];
5986 #endif
5987         struct Rect *door_rect = &door_rect_list[door_index];
5988         Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5989                                   bitmap_db_door_2);
5990         Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5991         int current_door_state = door_state & door_token;
5992         boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5993         boolean door_closing = !door_opening;
5994         boolean part_opening = (is_panel ? door_closing : door_opening);
5995         boolean part_closing = !part_opening;
5996         int start_step = (part_opening ? pos->start_step_opening :
5997                           pos->start_step_closing);
5998         int step_delay = pos->step_delay;
5999         int step_factor = step_delay / max_step_delay;
6000         int k1 = (step_factor ? k / step_factor + 1 : k);
6001         int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6002         int kk = (k2 < 0 ? 0 : k2);
6003         int src_x, src_y, src_xx, src_yy;
6004         int dst_x, dst_y, dst_xx, dst_yy;
6005         int width, height;
6006
6007 #if 0
6008         if (k == 0 && is_panel && door_token == DOOR_2)
6009           printf("::: %d, %d\n", g->width, g->height);
6010 #endif
6011
6012 #if 0
6013         if (DOOR_PART_IS_PANEL(nr))
6014         {
6015           int start_step = pos->start_step;
6016
6017           k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6018           kk = (k2 < 0 ? 0 : k2);
6019         }
6020 #endif
6021
6022 #if 0
6023         // !!! TEST !!! 
6024         if (nr != 16 && nr != 0)
6025           continue;
6026 #endif
6027
6028 #if 0
6029         // !!! TEST !!! 
6030         if (!is_panel)
6031           continue;
6032 #endif
6033
6034 #if 1
6035         if (door_part_skip[nr])
6036           continue;
6037 #endif
6038
6039         if (!(door_state & door_token))
6040           continue;
6041
6042         if (!g->bitmap)
6043           continue;
6044
6045 #if 0
6046         if (current_move_delay % step_delay)
6047           continue;
6048 #endif
6049
6050         // draw door panel
6051
6052         if (!door_panel_drawn[door_index])
6053         {
6054 #if 1
6055           ClearRectangle(drawto, door_rect->x, door_rect->y,
6056                          door_rect->width, door_rect->height);
6057 #else
6058           BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6059                      door_rect->width, door_rect->height,
6060                      door_rect->x, door_rect->y);
6061 #endif
6062
6063           door_panel_drawn[door_index] = TRUE;
6064         }
6065
6066         // draw opening or closing door parts
6067
6068         if (pos->step_xoffset < 0)      // door part on right side
6069         {
6070           src_xx = 0;
6071           dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6072           width = g->width;
6073
6074           if (dst_xx + width > door_rect->width)
6075             width = door_rect->width - dst_xx;
6076         }
6077         else                            // door part on left side
6078         {
6079           src_xx = 0;
6080           dst_xx = pos->x - kk * pos->step_xoffset;
6081
6082           if (dst_xx < 0)
6083           {
6084             src_xx = ABS(dst_xx);
6085             dst_xx = 0;
6086           }
6087
6088           width = g->width - src_xx;
6089
6090           // printf("::: k == %d [%d] \n", k, start_step);
6091         }
6092
6093         if (pos->step_yoffset < 0)      // door part on bottom side
6094         {
6095           src_yy = 0;
6096           dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6097           height = g->height;
6098
6099           if (dst_yy + height > door_rect->height)
6100             height = door_rect->height - dst_yy;
6101         }
6102         else                            // door part on top side
6103         {
6104           src_yy = 0;
6105           dst_yy = pos->y - kk * pos->step_yoffset;
6106
6107           if (dst_yy < 0)
6108           {
6109             src_yy = ABS(dst_yy);
6110             dst_yy = 0;
6111           }
6112
6113           height = g->height - src_yy;
6114         }
6115
6116         if (is_panel)
6117         {
6118 #if 1
6119           src_x = src_xx;
6120           src_y = src_yy;
6121 #else
6122           src_x = panel_pos->x + src_xx;
6123           src_y = panel_pos->y + src_yy;
6124 #endif
6125         }
6126         else
6127         {
6128           src_x = g->src_x + src_xx;
6129           src_y = g->src_y + src_yy;
6130         }
6131
6132         dst_x = door_rect->x + dst_xx;
6133         dst_y = door_rect->y + dst_yy;
6134
6135 #if 0
6136         if (DOOR_PART_IS_PANEL(nr))
6137         {
6138           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6139                  width, height, g->width, g->height, src_x, src_y);
6140         }
6141 #endif
6142
6143         if (width  >= 0 && width  <= g->width &&
6144             height >= 0 && height <= g->height)
6145         {
6146           if (is_panel || !pos->draw_masked)
6147             BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6148                        dst_x, dst_y);
6149           else
6150             BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6151                              dst_x, dst_y);
6152         }
6153
6154 #if 0
6155         if (DOOR_PART_IS_PANEL(nr))
6156         {
6157           bitmap = bitmap_db_door;
6158           src_x = panel_pos->x + src_xx;
6159           src_y = panel_pos->y + src_yy;
6160
6161           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6162                  width, height, g->width, g->height, src_x, src_y);
6163
6164           if (width  >= 0 && width  <= g->width &&
6165               height >= 0 && height <= g->height)
6166             BlitBitmap(bitmap, drawto, src_x, src_y,
6167                              width, height,
6168                              dst_x, dst_y);
6169         }
6170 #endif
6171
6172         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6173
6174 #if 1
6175         if ((part_opening && (width < 0         || height < 0)) ||
6176             (part_closing && (width >= g->width && height >= g->height)))
6177           door_part_done[nr] = TRUE;
6178 #else
6179         if ((door_opening && (width < 0         || height < 0)) ||
6180             (door_closing && (width >= g->width && height >= g->height)))
6181           door_part_done[nr] = TRUE;
6182 #endif
6183
6184 #if 1
6185         // continue door part animations, but not panel after door has closed
6186         if (!door_part_done[nr] &&
6187             !(is_panel && door_closing && panel_has_doors[door_index]))
6188           door_part_done_all = FALSE;
6189 #else
6190         // continue door part animations, but not panel after door has closed
6191         if (!door_part_done[nr] && !(is_panel && door_closing))
6192           door_part_done_all = FALSE;
6193 #endif
6194
6195 #if 0
6196         if (!door_part_done[nr])
6197           printf("::: k == %d, nr == %d\n", k, nr);
6198 #endif
6199       }
6200
6201       if (!(door_state & DOOR_NO_DELAY))
6202       {
6203         BackToFront();
6204
6205         if (game_status == GAME_MODE_MAIN)
6206           DoAnimation();
6207
6208         WaitUntilDelayReached(&door_delay, door_delay_value);
6209
6210         current_move_delay += max_step_delay;
6211       }
6212
6213 #if 0
6214       door_part_done_all = TRUE;
6215
6216       for (i = 0; i < MAX_DOOR_PARTS; i++)
6217         if (!door_part_done[i] &&
6218             !(DOOR_PART_IS_PANEL(i) && door_closing))
6219           door_part_done_all = FALSE;
6220 #endif
6221 #if 1
6222       if (door_part_done_all)
6223         break;
6224 #endif
6225     }
6226   }
6227
6228   if (door_state & DOOR_ACTION_1)
6229     door1 = door_state & DOOR_ACTION_1;
6230   if (door_state & DOOR_ACTION_2)
6231     door2 = door_state & DOOR_ACTION_2;
6232
6233 #if 0
6234   printf("::: DOORS DONE %08x\n", door_state);
6235   Delay(3000);
6236   printf("::: GO!\n");
6237 #endif
6238
6239   return (door1 | door2);
6240 }
6241
6242 #else
6243
6244 // ========== OLD ==============================================================
6245
6246 unsigned int MoveDoor(unsigned int door_state)
6247 {
6248   static int door1 = DOOR_OPEN_1;
6249   static int door2 = DOOR_CLOSE_2;
6250   unsigned int door_delay = 0;
6251   unsigned int door_delay_value;
6252   int stepsize = 1;
6253
6254 #if 1
6255   if (door_1.width < 0 || door_1.width > DXSIZE)
6256     door_1.width = DXSIZE;
6257   if (door_1.height < 0 || door_1.height > DYSIZE)
6258     door_1.height = DYSIZE;
6259   if (door_2.width < 0 || door_2.width > VXSIZE)
6260     door_2.width = VXSIZE;
6261   if (door_2.height < 0 || door_2.height > VYSIZE)
6262     door_2.height = VYSIZE;
6263 #endif
6264
6265   if (door_state == DOOR_GET_STATE)
6266     return (door1 | door2);
6267
6268   if (door_state & DOOR_SET_STATE)
6269   {
6270     if (door_state & DOOR_ACTION_1)
6271       door1 = door_state & DOOR_ACTION_1;
6272     if (door_state & DOOR_ACTION_2)
6273       door2 = door_state & DOOR_ACTION_2;
6274
6275     return (door1 | door2);
6276   }
6277
6278   if (!(door_state & DOOR_FORCE_REDRAW))
6279   {
6280     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6281       door_state &= ~DOOR_OPEN_1;
6282     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6283       door_state &= ~DOOR_CLOSE_1;
6284     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6285       door_state &= ~DOOR_OPEN_2;
6286     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6287       door_state &= ~DOOR_CLOSE_2;
6288   }
6289
6290   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6291                       door_2.step_delay);
6292
6293   // door_delay_value *= 4;     // !!! TEST ONLY !!!
6294
6295   if (setup.quick_doors)
6296   {
6297     stepsize = 20;              /* must be chosen to always draw last frame */
6298     door_delay_value = 0;
6299   }
6300
6301   if (global.autoplay_leveldir)
6302   {
6303     door_state |= DOOR_NO_DELAY;
6304     door_state &= ~DOOR_CLOSE_ALL;
6305   }
6306
6307 #if 1
6308   if (game_status == GAME_MODE_EDITOR)
6309     door_state |= DOOR_NO_DELAY;
6310 #endif
6311
6312   if (door_state & DOOR_ACTION)
6313   {
6314 #if 1
6315     struct GraphicInfo *g1_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6316     struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6317     struct GraphicInfo *g2_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6318     struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6319     int door_1_left_width   = g1_left->width;
6320     int door_1_left_height  = g1_left->height;
6321     int door_1_right_width  = g1_right->width;
6322     int door_1_right_height = g1_right->height;
6323     int door_2_left_width   = g2_left->width;
6324     int door_2_left_height  = g2_left->height;
6325     int door_2_right_width  = g2_right->width;
6326     int door_2_right_height = g2_right->height;
6327     int door_1_width  = MAX(door_1_left_width,  door_1_right_width);
6328     int door_1_height = MAX(door_1_left_height, door_1_right_height);
6329     int door_2_width  = MAX(door_2_left_width,  door_2_right_width);
6330     int door_2_height = MAX(door_2_left_height, door_2_right_height);
6331 #endif
6332     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6333     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6334     boolean door_1_done = (!handle_door_1);
6335     boolean door_2_done = (!handle_door_2);
6336     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6337     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6338 #if 1
6339 #if 1
6340     int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6341     int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6342 #else
6343     int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6344     int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6345 #endif
6346 #else
6347     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6348     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6349 #endif
6350     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6351     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6352     // int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
6353     int door_size     = (handle_door_2 ? door_size_2     : door_size_1);
6354     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6355     int door_skip = max_door_size - door_size;
6356     int end = door_size;
6357     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6358     int k;
6359
6360     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6361     {
6362       /* opening door sound has priority over simultaneously closing door */
6363       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6364         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6365       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6366         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6367     }
6368
6369     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6370     {
6371       int x = k;
6372 #if 0
6373       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6374       GC gc = bitmap->stored_clip_gc;
6375 #endif
6376
6377       if (door_state & DOOR_ACTION_1 &&
6378           x * door_1.step_offset <= door_size_1)
6379       {
6380         int a = MIN(x * door_1.step_offset, end);
6381         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6382 #if 1
6383         int i = p;
6384 #else
6385         int i = p + door_skip;
6386 #endif
6387
6388 #if 1
6389         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6390         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6391         Bitmap *bm_left  = g_left->bitmap;
6392         Bitmap *bm_right = g_right->bitmap;
6393         GC gc_left  = bm_left->stored_clip_gc;
6394         GC gc_right = bm_right->stored_clip_gc;
6395 #endif
6396
6397         int classic_dxsize = 100;
6398         int classic_dysize = 280;
6399         boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6400                                        DYSIZE == classic_dysize);
6401
6402         if (door_1.anim_mode & ANIM_STATIC_PANEL)
6403         {
6404           BlitBitmap(bitmap_db_door, drawto,
6405                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6406                      DXSIZE, DYSIZE, DX, DY);
6407         }
6408         else if (x <= a)
6409         {
6410           BlitBitmap(bitmap_db_door, drawto,
6411                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6412                      DXSIZE, DYSIZE - p / 2, DX, DY);
6413
6414 #if 1
6415           // printf("::: p == %d\n", p);
6416           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6417 #endif
6418         }
6419
6420         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6421         {
6422 #if 1
6423           int src1_x = g_right->src_x;
6424           int src1_y = g_right->src_y;
6425           int src2_x = g_left->src_x + g_left->width - i;
6426           int src2_y = g_left->src_y;
6427           int dst1_x = DX + DXSIZE - i;
6428           int dst1_y = DY;
6429           int dst2_x = DX;
6430           int dst2_y = DY;
6431           int width = i;
6432           int height = DYSIZE;
6433
6434           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6435           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6436                            dst1_x, dst1_y);
6437
6438           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6439           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6440                            dst2_x, dst2_y);
6441 #else
6442           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6443           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6444           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6445           int dst2_x = DX,              dst2_y = DY;
6446           int width = i, height = DYSIZE;
6447
6448           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6449           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6450                            dst1_x, dst1_y);
6451
6452           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6453           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6454                            dst2_x, dst2_y);
6455 #endif
6456         }
6457         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6458         {
6459 #if 1
6460           int src1_x = g_right->src_x;
6461           int src1_y = g_right->src_y;
6462           int src2_x = g_left->src_x;
6463           int src2_y = g_left->src_y + g_left->height - i;
6464           int dst1_x = DX;
6465           int dst1_y = DY + DYSIZE - i;
6466           int dst2_x = DX;
6467           int dst2_y = DY;
6468           int width = DXSIZE;
6469           int height = i;
6470
6471           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6472           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6473                            dst1_x, dst1_y);
6474
6475           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6476           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6477                            dst2_x, dst2_y);
6478 #else
6479           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6480           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6481           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
6482           int dst2_x = DX,              dst2_y = DY;
6483           int width = DXSIZE, height = i;
6484
6485           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6486           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6487                            dst1_x, dst1_y);
6488
6489           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6490           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6491                            dst2_x, dst2_y);
6492 #endif
6493         }
6494         else if (classic_door_1_size && x <= DXSIZE)    /* ANIM_DEFAULT */
6495         {
6496           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6497
6498 #if 1
6499           int src1_x = g_right->src_x;
6500           int src1_y = g_right->src_y;
6501           int src2_x = g_left->src_x + g_left->width - i;
6502           int src2_y = g_left->src_y;
6503           int dst1_x = DX + DXSIZE - i;
6504           int dst1_y = DY;
6505           int dst2_x = DX;
6506           int dst2_y = DY;
6507           int width = i;
6508           int height1 = 63, height2 = DYSIZE / 2 - height1;
6509           int ypos1 = 0, ypos2 = height2;
6510           int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6511
6512           SetClipOrigin(bm_right, gc_right,
6513                         dst1_x - src1_x, dst1_y - src1_y + j);
6514           BlitBitmapMasked(bm_right, drawto,
6515                            src1_x, src1_y + ypos1, width, height2,
6516                            dst1_x, dst1_y + ypos1 + j);
6517           BlitBitmapMasked(bm_right, drawto,
6518                            src1_x, src1_y + ypos3, width, height1,
6519                            dst1_x, dst1_y + ypos3 + j);
6520           SetClipOrigin(bm_left, gc_left,
6521                         dst2_x - src2_x, dst2_y - src2_y - j);
6522           BlitBitmapMasked(bm_left, drawto,
6523                            src2_x, src2_y + ypos1 + j, width, height2 - j,
6524                            dst2_x, dst2_y + ypos1);
6525           BlitBitmapMasked(bm_left, drawto,
6526                            src2_x, src2_y + ypos3, width, height1,
6527                            dst2_x, dst2_y + ypos3 - j);
6528
6529           SetClipOrigin(bm_left, gc_left,
6530                         dst2_x - src2_x, dst2_y - src2_y - j);
6531           BlitBitmapMasked(bm_left, drawto,
6532                            src2_x, src2_y + ypos2, width, height1,
6533                            dst2_x, dst2_y + ypos2 - j);
6534           BlitBitmapMasked(bm_left, drawto,
6535                            src2_x, src2_y + ypos4, width, height2,
6536                            dst2_x, dst2_y + ypos4 - j);
6537           SetClipOrigin(bm_right, gc_right,
6538                         dst1_x - src1_x, dst1_y - src1_y + j);
6539           BlitBitmapMasked(bm_right, drawto,
6540                            src1_x, src1_y + ypos2, width, height1,
6541                            dst1_x, dst1_y + ypos2 + j);
6542           BlitBitmapMasked(bm_right, drawto,
6543                            src1_x, src1_y + ypos4, width, height2 - j,
6544                            dst1_x, dst1_y + ypos4 + j);
6545
6546 #else
6547           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6548           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6549           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6550           int dst2_x = DX,              dst2_y = DY;
6551           int width = i, height = DYSIZE;
6552           int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6553
6554           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6555           BlitBitmapMasked(bitmap, drawto,
6556                            src1_x, src1_y, width, ypos2,
6557                            dst1_x, dst1_y + j);
6558           BlitBitmapMasked(bitmap, drawto,
6559                            src1_x, src1_y + ypos3, width, ypos1,
6560                            dst1_x, dst1_y + ypos3 + j);
6561           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6562           BlitBitmapMasked(bitmap, drawto,
6563                            src2_x, src2_y + j, width, ypos2 - j,
6564                            dst2_x, dst2_y);
6565           BlitBitmapMasked(bitmap, drawto,
6566                            src2_x, src2_y + ypos3, width, ypos1,
6567                            dst2_x, dst2_y + ypos3 - j);
6568
6569           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6570           BlitBitmapMasked(bitmap, drawto,
6571                            src2_x, src2_y + ypos2, width, ypos1,
6572                            dst2_x, dst2_y + ypos2 - j);
6573           BlitBitmapMasked(bitmap, drawto,
6574                            src2_x, src2_y + ypos4, width, ypos2,
6575                            dst2_x, dst2_y + ypos4 - j);
6576           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6577           BlitBitmapMasked(bitmap, drawto,
6578                            src1_x, src1_y + ypos2, width, ypos1,
6579                            dst1_x, dst1_y + ypos2 + j);
6580           BlitBitmapMasked(bitmap, drawto,
6581                            src1_x, src1_y + ypos4, width, ypos2 - j,
6582                            dst1_x, dst1_y + ypos4 + j);
6583
6584           /*
6585           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6586           BlitBitmapMasked(bitmap, drawto,
6587                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6588                            DX + DXSIZE - i, DY + j);
6589           BlitBitmapMasked(bitmap, drawto,
6590                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6591                            DX + DXSIZE - i, DY + 140 + j);
6592           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6593                         DY - (DOOR_GFX_PAGEY1 + j));
6594           BlitBitmapMasked(bitmap, drawto,
6595                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6596                            DX, DY);
6597           BlitBitmapMasked(bitmap, drawto,
6598                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6599                            DX, DY + 140 - j);
6600
6601           BlitBitmapMasked(bitmap, drawto,
6602                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6603                            DX, DY + 77 - j);
6604           BlitBitmapMasked(bitmap, drawto,
6605                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6606                            DX, DY + 203 - j);
6607           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6608           BlitBitmapMasked(bitmap, drawto,
6609                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6610                            DX + DXSIZE - i, DY + 77 + j);
6611           BlitBitmapMasked(bitmap, drawto,
6612                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6613                            DX + DXSIZE - i, DY + 203 + j);
6614           */
6615 #endif
6616         }
6617
6618         redraw_mask |= REDRAW_DOOR_1;
6619         door_1_done = (a == end);
6620       }
6621
6622       if (door_state & DOOR_ACTION_2 &&
6623           x * door_2.step_offset <= door_size_2)
6624       {
6625         int a = MIN(x * door_2.step_offset, door_size);
6626         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6627         int i = p + door_skip;
6628
6629 #if 1
6630         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6631         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6632         Bitmap *bm_left  = g_left->bitmap;
6633         Bitmap *bm_right = g_right->bitmap;
6634         GC gc_left  = bm_left->stored_clip_gc;
6635         GC gc_right = bm_right->stored_clip_gc;
6636 #endif
6637
6638         int classic_vxsize = 100;
6639         int classic_vysize = 100;
6640         boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6641                                        VYSIZE == classic_vysize);
6642
6643         if (door_2.anim_mode & ANIM_STATIC_PANEL)
6644         {
6645           BlitBitmap(bitmap_db_door, drawto,
6646                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6647                      VXSIZE, VYSIZE, VX, VY);
6648         }
6649         else if (x <= VYSIZE)
6650         {
6651           BlitBitmap(bitmap_db_door, drawto,
6652                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6653                      VXSIZE, VYSIZE - p / 2, VX, VY);
6654
6655           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6656         }
6657
6658         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6659         {
6660 #if 1
6661           int src1_x = g_right->src_x;
6662           int src1_y = g_right->src_y;
6663           int src2_x = g_left->src_x + g_left->width - i;
6664           int src2_y = g_left->src_y;
6665           int dst1_x = VX + VXSIZE - i;
6666           int dst1_y = VY;
6667           int dst2_x = VX;
6668           int dst2_y = VY;
6669           int width = i;
6670           int height = VYSIZE;
6671
6672           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6673           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6674                            dst1_x, dst1_y);
6675
6676           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6677           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6678                            dst2_x, dst2_y);
6679 #else
6680           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6681           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6682           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6683           int dst2_x = VX,              dst2_y = VY;
6684           int width = i, height = VYSIZE;
6685
6686           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6687           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6688                            dst1_x, dst1_y);
6689
6690           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6691           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6692                            dst2_x, dst2_y);
6693 #endif
6694         }
6695         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6696         {
6697 #if 1
6698           int src1_x = g_right->src_x;
6699           int src1_y = g_right->src_y;
6700           int src2_x = g_left->src_x;
6701           int src2_y = g_left->src_y + g_left->height - i;
6702           int dst1_x = VX;
6703           int dst1_y = VY + VYSIZE - i;
6704           int dst2_x = VX;
6705           int dst2_y = VY;
6706           int width = VXSIZE;
6707           int height = i;
6708
6709           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6710           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6711                            dst1_x, dst1_y);
6712
6713           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6714           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6715                            dst2_x, dst2_y);
6716 #else
6717           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6718           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6719           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
6720           int dst2_x = VX,              dst2_y = VY;
6721           int width = VXSIZE, height = i;
6722
6723           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6724           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6725                            dst1_x, dst1_y);
6726
6727           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6728           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6729                            dst2_x, dst2_y);
6730 #endif
6731         }
6732         else if (classic_door_2_size && x <= VXSIZE)    /* ANIM_DEFAULT */
6733         {
6734           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6735
6736 #if 1
6737           int src1_x = g_right->src_x;
6738           int src1_y = g_right->src_y;
6739           int src2_x = g_left->src_x + g_left->width - i;
6740           int src2_y = g_left->src_y;
6741           int dst1_x = VX + VXSIZE - i;
6742           int dst1_y = VY;
6743           int dst2_x = VX;
6744           int dst2_y = VY;
6745           int width = i;
6746           int height = VYSIZE / 2;
6747           int ypos1 = 0, ypos2 = VYSIZE / 2;
6748
6749           SetClipOrigin(bm_right, gc_right,
6750                         dst1_x - src1_x, dst1_y - src1_y + j);
6751           BlitBitmapMasked(bm_right, drawto,
6752                            src1_x, src1_y + ypos1, width, height,
6753                            dst1_x, dst1_y + ypos1 + j);
6754           SetClipOrigin(bm_left, gc_left,
6755                         dst2_x - src2_x, dst2_y - src2_y - j);
6756           BlitBitmapMasked(bm_left, drawto,
6757                            src2_x, src2_y + ypos1 + j, width, height - j,
6758                            dst2_x, dst2_y + ypos1);
6759
6760           SetClipOrigin(bm_left, gc_left,
6761                         dst2_x - src2_x, dst2_y - src2_y - j);
6762           BlitBitmapMasked(bm_left, drawto,
6763                            src2_x, src2_y + ypos2, width, height,
6764                            dst2_x, dst2_y + ypos2 - j);
6765           SetClipOrigin(bm_right, gc_right,
6766                         dst1_x - src1_x, dst1_y - src1_y + j);
6767           BlitBitmapMasked(bm_right, drawto,
6768                            src1_x, src1_y + ypos2, width, height - j,
6769                            dst1_x, dst1_y + ypos2 + j);
6770 #else
6771           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6772           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6773           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6774           int dst2_x = VX,              dst2_y = VY;
6775           int width = i, height = VYSIZE;
6776           int ypos = VYSIZE / 2;
6777
6778           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6779           BlitBitmapMasked(bitmap, drawto,
6780                            src1_x, src1_y, width, ypos,
6781                            dst1_x, dst1_y + j);
6782           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6783           BlitBitmapMasked(bitmap, drawto,
6784                            src2_x, src2_y + j, width, ypos - j,
6785                            dst2_x, dst2_y);
6786
6787           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6788           BlitBitmapMasked(bitmap, drawto,
6789                            src2_x, src2_y + ypos, width, ypos,
6790                            dst2_x, dst2_y + ypos - j);
6791           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6792           BlitBitmapMasked(bitmap, drawto,
6793                            src1_x, src1_y + ypos, width, ypos - j,
6794                            dst1_x, dst1_y + ypos + j);
6795
6796           /*
6797           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6798           BlitBitmapMasked(bitmap, drawto,
6799                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6800                            VX + VXSIZE - i, VY + j);
6801           SetClipOrigin(bitmap, gc,
6802                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6803           BlitBitmapMasked(bitmap, drawto,
6804                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6805                            VX, VY);
6806
6807           BlitBitmapMasked(bitmap, drawto,
6808                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6809                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6810           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6811           BlitBitmapMasked(bitmap, drawto,
6812                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6813                            i, VYSIZE / 2 - j,
6814                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6815           */
6816 #endif
6817         }
6818
6819         redraw_mask |= REDRAW_DOOR_2;
6820         door_2_done = (a == VXSIZE);
6821       }
6822
6823       if (!(door_state & DOOR_NO_DELAY))
6824       {
6825         BackToFront();
6826
6827         if (game_status == GAME_MODE_MAIN)
6828           DoAnimation();
6829
6830         WaitUntilDelayReached(&door_delay, door_delay_value);
6831       }
6832     }
6833   }
6834
6835   if (door_state & DOOR_ACTION_1)
6836     door1 = door_state & DOOR_ACTION_1;
6837   if (door_state & DOOR_ACTION_2)
6838     door2 = door_state & DOOR_ACTION_2;
6839
6840   return (door1 | door2);
6841 }
6842
6843 #endif
6844
6845 void DrawSpecialEditorDoor()
6846 {
6847 #if 1
6848   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6849   int top_border_width = gfx1->width;
6850   int top_border_height = gfx1->height;
6851   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6852   int ex = EX - outer_border;
6853   int ey = EY - outer_border;
6854   int vy = VY - outer_border;
6855   int exsize = EXSIZE + 2 * outer_border;
6856
6857   CloseDoor(DOOR_CLOSE_2);
6858
6859   /* draw bigger level editor toolbox window */
6860   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6861              top_border_width, top_border_height, ex, ey - top_border_height);
6862   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6863              exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6864 #else
6865   /* draw bigger level editor toolbox window */
6866   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6867              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6868              EX - 4, EY - 12);
6869   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6870              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6871              EX - 6, EY - 4);
6872 #endif
6873
6874   redraw_mask |= REDRAW_ALL;
6875 }
6876
6877 void UndrawSpecialEditorDoor()
6878 {
6879 #if 1
6880   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6881   int top_border_width = gfx1->width;
6882   int top_border_height = gfx1->height;
6883   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6884   int ex = EX - outer_border;
6885   int ey = EY - outer_border;
6886   int ey_top = ey - top_border_height;
6887   int exsize = EXSIZE + 2 * outer_border;
6888   int eysize = EYSIZE + 2 * outer_border;
6889
6890   /* draw normal tape recorder window */
6891   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6892   {
6893     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6894                ex, ey_top, top_border_width, top_border_height,
6895                ex, ey_top);
6896     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6897                ex, ey, exsize, eysize, ex, ey);
6898   }
6899   else
6900   {
6901     // if screen background is set to "[NONE]", clear editor toolbox window
6902     ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6903     ClearRectangle(drawto, ex, ey, exsize, eysize);
6904   }
6905 #else
6906   /* draw normal tape recorder window */
6907   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6908              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6909              EX - 6, EY - 12);
6910 #endif
6911
6912   redraw_mask |= REDRAW_ALL;
6913 }
6914
6915
6916 /* ---------- new tool button stuff ---------------------------------------- */
6917
6918 #if 1
6919
6920 static struct
6921 {
6922   int graphic;
6923   struct TextPosInfo *pos;
6924   int gadget_id;
6925   char *infotext;
6926 } toolbutton_info[NUM_TOOL_BUTTONS] =
6927 {
6928   {
6929     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
6930     TOOL_CTRL_ID_YES,                   "yes"
6931   },
6932   {
6933     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
6934     TOOL_CTRL_ID_NO,                    "no"
6935   },
6936   {
6937     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
6938     TOOL_CTRL_ID_CONFIRM,               "confirm"
6939   },
6940   {
6941     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
6942     TOOL_CTRL_ID_PLAYER_1,              "player 1"
6943   },
6944   {
6945     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
6946     TOOL_CTRL_ID_PLAYER_2,              "player 2"
6947   },
6948   {
6949     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
6950     TOOL_CTRL_ID_PLAYER_3,              "player 3"
6951   },
6952   {
6953     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
6954     TOOL_CTRL_ID_PLAYER_4,              "player 4"
6955   }
6956 };
6957
6958 void CreateToolButtons()
6959 {
6960   int i;
6961
6962   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6963   {
6964     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6965     struct TextPosInfo *pos = toolbutton_info[i].pos;
6966     struct GadgetInfo *gi;
6967     Bitmap *deco_bitmap = None;
6968     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6969     unsigned int event_mask = GD_EVENT_RELEASED;
6970     int dx = DX;
6971     int dy = DY;
6972     int gd_x = gfx->src_x;
6973     int gd_y = gfx->src_y;
6974     int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6975     int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6976     int id = i;
6977
6978     if (global.use_envelope_request)
6979       setRequestPosition(&dx, &dy, TRUE);
6980
6981     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6982     {
6983       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6984
6985       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6986                             pos->size, &deco_bitmap, &deco_x, &deco_y);
6987       deco_xpos = (gfx->width  - pos->size) / 2;
6988       deco_ypos = (gfx->height - pos->size) / 2;
6989     }
6990
6991     gi = CreateGadget(GDI_CUSTOM_ID, id,
6992                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
6993                       GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6994                       GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6995                       GDI_WIDTH, gfx->width,
6996                       GDI_HEIGHT, gfx->height,
6997                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6998                       GDI_STATE, GD_BUTTON_UNPRESSED,
6999                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7000                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7001                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7002                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7003                       GDI_DECORATION_SIZE, pos->size, pos->size,
7004                       GDI_DECORATION_SHIFTING, 1, 1,
7005                       GDI_DIRECT_DRAW, FALSE,
7006                       GDI_EVENT_MASK, event_mask,
7007                       GDI_CALLBACK_ACTION, HandleToolButtons,
7008                       GDI_END);
7009
7010     if (gi == NULL)
7011       Error(ERR_EXIT, "cannot create gadget");
7012
7013     tool_gadget[id] = gi;
7014   }
7015 }
7016
7017 #else
7018
7019 /* graphic position values for tool buttons */
7020 #define TOOL_BUTTON_YES_XPOS            2
7021 #define TOOL_BUTTON_YES_YPOS            250
7022 #define TOOL_BUTTON_YES_GFX_YPOS        0
7023 #define TOOL_BUTTON_YES_XSIZE           46
7024 #define TOOL_BUTTON_YES_YSIZE           28
7025 #define TOOL_BUTTON_NO_XPOS             52
7026 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
7027 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
7028 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
7029 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
7030 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
7031 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
7032 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
7033 #define TOOL_BUTTON_CONFIRM_XSIZE       96
7034 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
7035 #define TOOL_BUTTON_PLAYER_XSIZE        30
7036 #define TOOL_BUTTON_PLAYER_YSIZE        30
7037 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
7038 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
7039 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7040 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7041 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7042                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7043 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7044                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7045 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7046                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7047 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7048                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7049 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7050                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7051 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7052                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7053 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7054                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7055 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7056                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7057
7058 static struct
7059 {
7060   int xpos, ypos;
7061   int x, y;
7062   int width, height;
7063   int gadget_id;
7064   char *infotext;
7065 } toolbutton_info[NUM_TOOL_BUTTONS] =
7066 {
7067   {
7068     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
7069     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
7070     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
7071     TOOL_CTRL_ID_YES,
7072     "yes"
7073   },
7074   {
7075     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
7076     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
7077     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
7078     TOOL_CTRL_ID_NO,
7079     "no"
7080   },
7081   {
7082     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
7083     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
7084     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
7085     TOOL_CTRL_ID_CONFIRM,
7086     "confirm"
7087   },
7088   {
7089     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7090     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
7091     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7092     TOOL_CTRL_ID_PLAYER_1,
7093     "player 1"
7094   },
7095   {
7096     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7097     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
7098     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7099     TOOL_CTRL_ID_PLAYER_2,
7100     "player 2"
7101   },
7102   {
7103     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7104     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
7105     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7106     TOOL_CTRL_ID_PLAYER_3,
7107     "player 3"
7108   },
7109   {
7110     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7111     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
7112     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7113     TOOL_CTRL_ID_PLAYER_4,
7114     "player 4"
7115   }
7116 };
7117
7118 void CreateToolButtons()
7119 {
7120   int i;
7121
7122   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7123   {
7124     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7125     Bitmap *deco_bitmap = None;
7126     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7127     struct GadgetInfo *gi;
7128     unsigned int event_mask;
7129     int gd_xoffset, gd_yoffset;
7130     int gd_x1, gd_x2, gd_y;
7131     int id = i;
7132
7133     event_mask = GD_EVENT_RELEASED;
7134
7135     gd_xoffset = toolbutton_info[i].xpos;
7136     gd_yoffset = toolbutton_info[i].ypos;
7137     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7138     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7139     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7140
7141     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7142     {
7143       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7144
7145       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7146                            &deco_bitmap, &deco_x, &deco_y);
7147       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7148       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7149     }
7150
7151     gi = CreateGadget(GDI_CUSTOM_ID, id,
7152                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
7153                       GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7154                       GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7155                       GDI_WIDTH, toolbutton_info[i].width,
7156                       GDI_HEIGHT, toolbutton_info[i].height,
7157                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7158                       GDI_STATE, GD_BUTTON_UNPRESSED,
7159                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7160                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7161                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7162                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7163                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7164                       GDI_DECORATION_SHIFTING, 1, 1,
7165                       GDI_DIRECT_DRAW, FALSE,
7166                       GDI_EVENT_MASK, event_mask,
7167                       GDI_CALLBACK_ACTION, HandleToolButtons,
7168                       GDI_END);
7169
7170     if (gi == NULL)
7171       Error(ERR_EXIT, "cannot create gadget");
7172
7173     tool_gadget[id] = gi;
7174   }
7175 }
7176
7177 #endif
7178
7179 void FreeToolButtons()
7180 {
7181   int i;
7182
7183   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7184     FreeGadget(tool_gadget[i]);
7185 }
7186
7187 static void UnmapToolButtons()
7188 {
7189   int i;
7190
7191   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7192     UnmapGadget(tool_gadget[i]);
7193 }
7194
7195 static void HandleToolButtons(struct GadgetInfo *gi)
7196 {
7197   request_gadget_id = gi->custom_id;
7198 }
7199
7200 static struct Mapping_EM_to_RND_object
7201 {
7202   int element_em;
7203   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
7204   boolean is_backside;                  /* backside of moving element */
7205
7206   int element_rnd;
7207   int action;
7208   int direction;
7209 }
7210 em_object_mapping_list[] =
7211 {
7212   {
7213     Xblank,                             TRUE,   FALSE,
7214     EL_EMPTY,                           -1, -1
7215   },
7216   {
7217     Yacid_splash_eB,                    FALSE,  FALSE,
7218     EL_ACID_SPLASH_RIGHT,               -1, -1
7219   },
7220   {
7221     Yacid_splash_wB,                    FALSE,  FALSE,
7222     EL_ACID_SPLASH_LEFT,                -1, -1
7223   },
7224
7225 #ifdef EM_ENGINE_BAD_ROLL
7226   {
7227     Xstone_force_e,                     FALSE,  FALSE,
7228     EL_ROCK,                            -1, MV_BIT_RIGHT
7229   },
7230   {
7231     Xstone_force_w,                     FALSE,  FALSE,
7232     EL_ROCK,                            -1, MV_BIT_LEFT
7233   },
7234   {
7235     Xnut_force_e,                       FALSE,  FALSE,
7236     EL_NUT,                             -1, MV_BIT_RIGHT
7237   },
7238   {
7239     Xnut_force_w,                       FALSE,  FALSE,
7240     EL_NUT,                             -1, MV_BIT_LEFT
7241   },
7242   {
7243     Xspring_force_e,                    FALSE,  FALSE,
7244     EL_SPRING,                          -1, MV_BIT_RIGHT
7245   },
7246   {
7247     Xspring_force_w,                    FALSE,  FALSE,
7248     EL_SPRING,                          -1, MV_BIT_LEFT
7249   },
7250   {
7251     Xemerald_force_e,                   FALSE,  FALSE,
7252     EL_EMERALD,                         -1, MV_BIT_RIGHT
7253   },
7254   {
7255     Xemerald_force_w,                   FALSE,  FALSE,
7256     EL_EMERALD,                         -1, MV_BIT_LEFT
7257   },
7258   {
7259     Xdiamond_force_e,                   FALSE,  FALSE,
7260     EL_DIAMOND,                         -1, MV_BIT_RIGHT
7261   },
7262   {
7263     Xdiamond_force_w,                   FALSE,  FALSE,
7264     EL_DIAMOND,                         -1, MV_BIT_LEFT
7265   },
7266   {
7267     Xbomb_force_e,                      FALSE,  FALSE,
7268     EL_BOMB,                            -1, MV_BIT_RIGHT
7269   },
7270   {
7271     Xbomb_force_w,                      FALSE,  FALSE,
7272     EL_BOMB,                            -1, MV_BIT_LEFT
7273   },
7274 #endif  /* EM_ENGINE_BAD_ROLL */
7275
7276   {
7277     Xstone,                             TRUE,   FALSE,
7278     EL_ROCK,                            -1, -1
7279   },
7280   {
7281     Xstone_pause,                       FALSE,  FALSE,
7282     EL_ROCK,                            -1, -1
7283   },
7284   {
7285     Xstone_fall,                        FALSE,  FALSE,
7286     EL_ROCK,                            -1, -1
7287   },
7288   {
7289     Ystone_s,                           FALSE,  FALSE,
7290     EL_ROCK,                            ACTION_FALLING, -1
7291   },
7292   {
7293     Ystone_sB,                          FALSE,  TRUE,
7294     EL_ROCK,                            ACTION_FALLING, -1
7295   },
7296   {
7297     Ystone_e,                           FALSE,  FALSE,
7298     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7299   },
7300   {
7301     Ystone_eB,                          FALSE,  TRUE,
7302     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7303   },
7304   {
7305     Ystone_w,                           FALSE,  FALSE,
7306     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7307   },
7308   {
7309     Ystone_wB,                          FALSE,  TRUE,
7310     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7311   },
7312   {
7313     Xnut,                               TRUE,   FALSE,
7314     EL_NUT,                             -1, -1
7315   },
7316   {
7317     Xnut_pause,                         FALSE,  FALSE,
7318     EL_NUT,                             -1, -1
7319   },
7320   {
7321     Xnut_fall,                          FALSE,  FALSE,
7322     EL_NUT,                             -1, -1
7323   },
7324   {
7325     Ynut_s,                             FALSE,  FALSE,
7326     EL_NUT,                             ACTION_FALLING, -1
7327   },
7328   {
7329     Ynut_sB,                            FALSE,  TRUE,
7330     EL_NUT,                             ACTION_FALLING, -1
7331   },
7332   {
7333     Ynut_e,                             FALSE,  FALSE,
7334     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7335   },
7336   {
7337     Ynut_eB,                            FALSE,  TRUE,
7338     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7339   },
7340   {
7341     Ynut_w,                             FALSE,  FALSE,
7342     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7343   },
7344   {
7345     Ynut_wB,                            FALSE,  TRUE,
7346     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7347   },
7348   {
7349     Xbug_n,                             TRUE,   FALSE,
7350     EL_BUG_UP,                          -1, -1
7351   },
7352   {
7353     Xbug_e,                             TRUE,   FALSE,
7354     EL_BUG_RIGHT,                       -1, -1
7355   },
7356   {
7357     Xbug_s,                             TRUE,   FALSE,
7358     EL_BUG_DOWN,                        -1, -1
7359   },
7360   {
7361     Xbug_w,                             TRUE,   FALSE,
7362     EL_BUG_LEFT,                        -1, -1
7363   },
7364   {
7365     Xbug_gon,                           FALSE,  FALSE,
7366     EL_BUG_UP,                          -1, -1
7367   },
7368   {
7369     Xbug_goe,                           FALSE,  FALSE,
7370     EL_BUG_RIGHT,                       -1, -1
7371   },
7372   {
7373     Xbug_gos,                           FALSE,  FALSE,
7374     EL_BUG_DOWN,                        -1, -1
7375   },
7376   {
7377     Xbug_gow,                           FALSE,  FALSE,
7378     EL_BUG_LEFT,                        -1, -1
7379   },
7380   {
7381     Ybug_n,                             FALSE,  FALSE,
7382     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7383   },
7384   {
7385     Ybug_nB,                            FALSE,  TRUE,
7386     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7387   },
7388   {
7389     Ybug_e,                             FALSE,  FALSE,
7390     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7391   },
7392   {
7393     Ybug_eB,                            FALSE,  TRUE,
7394     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7395   },
7396   {
7397     Ybug_s,                             FALSE,  FALSE,
7398     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7399   },
7400   {
7401     Ybug_sB,                            FALSE,  TRUE,
7402     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7403   },
7404   {
7405     Ybug_w,                             FALSE,  FALSE,
7406     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7407   },
7408   {
7409     Ybug_wB,                            FALSE,  TRUE,
7410     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7411   },
7412   {
7413     Ybug_w_n,                           FALSE,  FALSE,
7414     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7415   },
7416   {
7417     Ybug_n_e,                           FALSE,  FALSE,
7418     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7419   },
7420   {
7421     Ybug_e_s,                           FALSE,  FALSE,
7422     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7423   },
7424   {
7425     Ybug_s_w,                           FALSE,  FALSE,
7426     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7427   },
7428   {
7429     Ybug_e_n,                           FALSE,  FALSE,
7430     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7431   },
7432   {
7433     Ybug_s_e,                           FALSE,  FALSE,
7434     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7435   },
7436   {
7437     Ybug_w_s,                           FALSE,  FALSE,
7438     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7439   },
7440   {
7441     Ybug_n_w,                           FALSE,  FALSE,
7442     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7443   },
7444   {
7445     Ybug_stone,                         FALSE,  FALSE,
7446     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
7447   },
7448   {
7449     Ybug_spring,                        FALSE,  FALSE,
7450     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
7451   },
7452   {
7453     Xtank_n,                            TRUE,   FALSE,
7454     EL_SPACESHIP_UP,                    -1, -1
7455   },
7456   {
7457     Xtank_e,                            TRUE,   FALSE,
7458     EL_SPACESHIP_RIGHT,                 -1, -1
7459   },
7460   {
7461     Xtank_s,                            TRUE,   FALSE,
7462     EL_SPACESHIP_DOWN,                  -1, -1
7463   },
7464   {
7465     Xtank_w,                            TRUE,   FALSE,
7466     EL_SPACESHIP_LEFT,                  -1, -1
7467   },
7468   {
7469     Xtank_gon,                          FALSE,  FALSE,
7470     EL_SPACESHIP_UP,                    -1, -1
7471   },
7472   {
7473     Xtank_goe,                          FALSE,  FALSE,
7474     EL_SPACESHIP_RIGHT,                 -1, -1
7475   },
7476   {
7477     Xtank_gos,                          FALSE,  FALSE,
7478     EL_SPACESHIP_DOWN,                  -1, -1
7479   },
7480   {
7481     Xtank_gow,                          FALSE,  FALSE,
7482     EL_SPACESHIP_LEFT,                  -1, -1
7483   },
7484   {
7485     Ytank_n,                            FALSE,  FALSE,
7486     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7487   },
7488   {
7489     Ytank_nB,                           FALSE,  TRUE,
7490     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7491   },
7492   {
7493     Ytank_e,                            FALSE,  FALSE,
7494     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7495   },
7496   {
7497     Ytank_eB,                           FALSE,  TRUE,
7498     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7499   },
7500   {
7501     Ytank_s,                            FALSE,  FALSE,
7502     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7503   },
7504   {
7505     Ytank_sB,                           FALSE,  TRUE,
7506     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7507   },
7508   {
7509     Ytank_w,                            FALSE,  FALSE,
7510     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7511   },
7512   {
7513     Ytank_wB,                           FALSE,  TRUE,
7514     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7515   },
7516   {
7517     Ytank_w_n,                          FALSE,  FALSE,
7518     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7519   },
7520   {
7521     Ytank_n_e,                          FALSE,  FALSE,
7522     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7523   },
7524   {
7525     Ytank_e_s,                          FALSE,  FALSE,
7526     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7527   },
7528   {
7529     Ytank_s_w,                          FALSE,  FALSE,
7530     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7531   },
7532   {
7533     Ytank_e_n,                          FALSE,  FALSE,
7534     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7535   },
7536   {
7537     Ytank_s_e,                          FALSE,  FALSE,
7538     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7539   },
7540   {
7541     Ytank_w_s,                          FALSE,  FALSE,
7542     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7543   },
7544   {
7545     Ytank_n_w,                          FALSE,  FALSE,
7546     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7547   },
7548   {
7549     Ytank_stone,                        FALSE,  FALSE,
7550     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
7551   },
7552   {
7553     Ytank_spring,                       FALSE,  FALSE,
7554     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
7555   },
7556   {
7557     Xandroid,                           TRUE,   FALSE,
7558     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
7559   },
7560   {
7561     Xandroid_1_n,                       FALSE,  FALSE,
7562     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7563   },
7564   {
7565     Xandroid_2_n,                       FALSE,  FALSE,
7566     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7567   },
7568   {
7569     Xandroid_1_e,                       FALSE,  FALSE,
7570     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7571   },
7572   {
7573     Xandroid_2_e,                       FALSE,  FALSE,
7574     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7575   },
7576   {
7577     Xandroid_1_w,                       FALSE,  FALSE,
7578     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7579   },
7580   {
7581     Xandroid_2_w,                       FALSE,  FALSE,
7582     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7583   },
7584   {
7585     Xandroid_1_s,                       FALSE,  FALSE,
7586     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7587   },
7588   {
7589     Xandroid_2_s,                       FALSE,  FALSE,
7590     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7591   },
7592   {
7593     Yandroid_n,                         FALSE,  FALSE,
7594     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7595   },
7596   {
7597     Yandroid_nB,                        FALSE,  TRUE,
7598     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7599   },
7600   {
7601     Yandroid_ne,                        FALSE,  FALSE,
7602     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
7603   },
7604   {
7605     Yandroid_neB,                       FALSE,  TRUE,
7606     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
7607   },
7608   {
7609     Yandroid_e,                         FALSE,  FALSE,
7610     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7611   },
7612   {
7613     Yandroid_eB,                        FALSE,  TRUE,
7614     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7615   },
7616   {
7617     Yandroid_se,                        FALSE,  FALSE,
7618     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
7619   },
7620   {
7621     Yandroid_seB,                       FALSE,  TRUE,
7622     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7623   },
7624   {
7625     Yandroid_s,                         FALSE,  FALSE,
7626     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7627   },
7628   {
7629     Yandroid_sB,                        FALSE,  TRUE,
7630     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7631   },
7632   {
7633     Yandroid_sw,                        FALSE,  FALSE,
7634     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
7635   },
7636   {
7637     Yandroid_swB,                       FALSE,  TRUE,
7638     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
7639   },
7640   {
7641     Yandroid_w,                         FALSE,  FALSE,
7642     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7643   },
7644   {
7645     Yandroid_wB,                        FALSE,  TRUE,
7646     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7647   },
7648   {
7649     Yandroid_nw,                        FALSE,  FALSE,
7650     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
7651   },
7652   {
7653     Yandroid_nwB,                       FALSE,  TRUE,
7654     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
7655   },
7656   {
7657     Xspring,                            TRUE,   FALSE,
7658     EL_SPRING,                          -1, -1
7659   },
7660   {
7661     Xspring_pause,                      FALSE,  FALSE,
7662     EL_SPRING,                          -1, -1
7663   },
7664   {
7665     Xspring_e,                          FALSE,  FALSE,
7666     EL_SPRING,                          -1, -1
7667   },
7668   {
7669     Xspring_w,                          FALSE,  FALSE,
7670     EL_SPRING,                          -1, -1
7671   },
7672   {
7673     Xspring_fall,                       FALSE,  FALSE,
7674     EL_SPRING,                          -1, -1
7675   },
7676   {
7677     Yspring_s,                          FALSE,  FALSE,
7678     EL_SPRING,                          ACTION_FALLING, -1
7679   },
7680   {
7681     Yspring_sB,                         FALSE,  TRUE,
7682     EL_SPRING,                          ACTION_FALLING, -1
7683   },
7684   {
7685     Yspring_e,                          FALSE,  FALSE,
7686     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7687   },
7688   {
7689     Yspring_eB,                         FALSE,  TRUE,
7690     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7691   },
7692   {
7693     Yspring_w,                          FALSE,  FALSE,
7694     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7695   },
7696   {
7697     Yspring_wB,                         FALSE,  TRUE,
7698     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7699   },
7700   {
7701     Yspring_kill_e,                     FALSE,  FALSE,
7702     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7703   },
7704   {
7705     Yspring_kill_eB,                    FALSE,  TRUE,
7706     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7707   },
7708   {
7709     Yspring_kill_w,                     FALSE,  FALSE,
7710     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7711   },
7712   {
7713     Yspring_kill_wB,                    FALSE,  TRUE,
7714     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7715   },
7716   {
7717     Xeater_n,                           TRUE,   FALSE,
7718     EL_YAMYAM_UP,                       -1, -1
7719   },
7720   {
7721     Xeater_e,                           TRUE,   FALSE,
7722     EL_YAMYAM_RIGHT,                    -1, -1
7723   },
7724   {
7725     Xeater_w,                           TRUE,   FALSE,
7726     EL_YAMYAM_LEFT,                     -1, -1
7727   },
7728   {
7729     Xeater_s,                           TRUE,   FALSE,
7730     EL_YAMYAM_DOWN,                     -1, -1
7731   },
7732   {
7733     Yeater_n,                           FALSE,  FALSE,
7734     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7735   },
7736   {
7737     Yeater_nB,                          FALSE,  TRUE,
7738     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7739   },
7740   {
7741     Yeater_e,                           FALSE,  FALSE,
7742     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7743   },
7744   {
7745     Yeater_eB,                          FALSE,  TRUE,
7746     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7747   },
7748   {
7749     Yeater_s,                           FALSE,  FALSE,
7750     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7751   },
7752   {
7753     Yeater_sB,                          FALSE,  TRUE,
7754     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7755   },
7756   {
7757     Yeater_w,                           FALSE,  FALSE,
7758     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7759   },
7760   {
7761     Yeater_wB,                          FALSE,  TRUE,
7762     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7763   },
7764   {
7765     Yeater_stone,                       FALSE,  FALSE,
7766     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
7767   },
7768   {
7769     Yeater_spring,                      FALSE,  FALSE,
7770     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
7771   },
7772   {
7773     Xalien,                             TRUE,   FALSE,
7774     EL_ROBOT,                           -1, -1
7775   },
7776   {
7777     Xalien_pause,                       FALSE,  FALSE,
7778     EL_ROBOT,                           -1, -1
7779   },
7780   {
7781     Yalien_n,                           FALSE,  FALSE,
7782     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7783   },
7784   {
7785     Yalien_nB,                          FALSE,  TRUE,
7786     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7787   },
7788   {
7789     Yalien_e,                           FALSE,  FALSE,
7790     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7791   },
7792   {
7793     Yalien_eB,                          FALSE,  TRUE,
7794     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7795   },
7796   {
7797     Yalien_s,                           FALSE,  FALSE,
7798     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7799   },
7800   {
7801     Yalien_sB,                          FALSE,  TRUE,
7802     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7803   },
7804   {
7805     Yalien_w,                           FALSE,  FALSE,
7806     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7807   },
7808   {
7809     Yalien_wB,                          FALSE,  TRUE,
7810     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7811   },
7812   {
7813     Yalien_stone,                       FALSE,  FALSE,
7814     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
7815   },
7816   {
7817     Yalien_spring,                      FALSE,  FALSE,
7818     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
7819   },
7820   {
7821     Xemerald,                           TRUE,   FALSE,
7822     EL_EMERALD,                         -1, -1
7823   },
7824   {
7825     Xemerald_pause,                     FALSE,  FALSE,
7826     EL_EMERALD,                         -1, -1
7827   },
7828   {
7829     Xemerald_fall,                      FALSE,  FALSE,
7830     EL_EMERALD,                         -1, -1
7831   },
7832   {
7833     Xemerald_shine,                     FALSE,  FALSE,
7834     EL_EMERALD,                         ACTION_TWINKLING, -1
7835   },
7836   {
7837     Yemerald_s,                         FALSE,  FALSE,
7838     EL_EMERALD,                         ACTION_FALLING, -1
7839   },
7840   {
7841     Yemerald_sB,                        FALSE,  TRUE,
7842     EL_EMERALD,                         ACTION_FALLING, -1
7843   },
7844   {
7845     Yemerald_e,                         FALSE,  FALSE,
7846     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7847   },
7848   {
7849     Yemerald_eB,                        FALSE,  TRUE,
7850     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7851   },
7852   {
7853     Yemerald_w,                         FALSE,  FALSE,
7854     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7855   },
7856   {
7857     Yemerald_wB,                        FALSE,  TRUE,
7858     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7859   },
7860   {
7861     Yemerald_eat,                       FALSE,  FALSE,
7862     EL_EMERALD,                         ACTION_COLLECTING, -1
7863   },
7864   {
7865     Yemerald_stone,                     FALSE,  FALSE,
7866     EL_NUT,                             ACTION_BREAKING, -1
7867   },
7868   {
7869     Xdiamond,                           TRUE,   FALSE,
7870     EL_DIAMOND,                         -1, -1
7871   },
7872   {
7873     Xdiamond_pause,                     FALSE,  FALSE,
7874     EL_DIAMOND,                         -1, -1
7875   },
7876   {
7877     Xdiamond_fall,                      FALSE,  FALSE,
7878     EL_DIAMOND,                         -1, -1
7879   },
7880   {
7881     Xdiamond_shine,                     FALSE,  FALSE,
7882     EL_DIAMOND,                         ACTION_TWINKLING, -1
7883   },
7884   {
7885     Ydiamond_s,                         FALSE,  FALSE,
7886     EL_DIAMOND,                         ACTION_FALLING, -1
7887   },
7888   {
7889     Ydiamond_sB,                        FALSE,  TRUE,
7890     EL_DIAMOND,                         ACTION_FALLING, -1
7891   },
7892   {
7893     Ydiamond_e,                         FALSE,  FALSE,
7894     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7895   },
7896   {
7897     Ydiamond_eB,                        FALSE,  TRUE,
7898     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7899   },
7900   {
7901     Ydiamond_w,                         FALSE,  FALSE,
7902     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7903   },
7904   {
7905     Ydiamond_wB,                        FALSE,  TRUE,
7906     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7907   },
7908   {
7909     Ydiamond_eat,                       FALSE,  FALSE,
7910     EL_DIAMOND,                         ACTION_COLLECTING, -1
7911   },
7912   {
7913     Ydiamond_stone,                     FALSE,  FALSE,
7914     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
7915   },
7916   {
7917     Xdrip_fall,                         TRUE,   FALSE,
7918     EL_AMOEBA_DROP,                     -1, -1
7919   },
7920   {
7921     Xdrip_stretch,                      FALSE,  FALSE,
7922     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7923   },
7924   {
7925     Xdrip_stretchB,                     FALSE,  TRUE,
7926     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7927   },
7928   {
7929     Xdrip_eat,                          FALSE,  FALSE,
7930     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
7931   },
7932   {
7933     Ydrip_s1,                           FALSE,  FALSE,
7934     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7935   },
7936   {
7937     Ydrip_s1B,                          FALSE,  TRUE,
7938     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7939   },
7940   {
7941     Ydrip_s2,                           FALSE,  FALSE,
7942     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7943   },
7944   {
7945     Ydrip_s2B,                          FALSE,  TRUE,
7946     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7947   },
7948   {
7949     Xbomb,                              TRUE,   FALSE,
7950     EL_BOMB,                            -1, -1
7951   },
7952   {
7953     Xbomb_pause,                        FALSE,  FALSE,
7954     EL_BOMB,                            -1, -1
7955   },
7956   {
7957     Xbomb_fall,                         FALSE,  FALSE,
7958     EL_BOMB,                            -1, -1
7959   },
7960   {
7961     Ybomb_s,                            FALSE,  FALSE,
7962     EL_BOMB,                            ACTION_FALLING, -1
7963   },
7964   {
7965     Ybomb_sB,                           FALSE,  TRUE,
7966     EL_BOMB,                            ACTION_FALLING, -1
7967   },
7968   {
7969     Ybomb_e,                            FALSE,  FALSE,
7970     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7971   },
7972   {
7973     Ybomb_eB,                           FALSE,  TRUE,
7974     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7975   },
7976   {
7977     Ybomb_w,                            FALSE,  FALSE,
7978     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7979   },
7980   {
7981     Ybomb_wB,                           FALSE,  TRUE,
7982     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7983   },
7984   {
7985     Ybomb_eat,                          FALSE,  FALSE,
7986     EL_BOMB,                            ACTION_ACTIVATING, -1
7987   },
7988   {
7989     Xballoon,                           TRUE,   FALSE,
7990     EL_BALLOON,                         -1, -1
7991   },
7992   {
7993     Yballoon_n,                         FALSE,  FALSE,
7994     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7995   },
7996   {
7997     Yballoon_nB,                        FALSE,  TRUE,
7998     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7999   },
8000   {
8001     Yballoon_e,                         FALSE,  FALSE,
8002     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
8003   },
8004   {
8005     Yballoon_eB,                        FALSE,  TRUE,
8006     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
8007   },
8008   {
8009     Yballoon_s,                         FALSE,  FALSE,
8010     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
8011   },
8012   {
8013     Yballoon_sB,                        FALSE,  TRUE,
8014     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
8015   },
8016   {
8017     Yballoon_w,                         FALSE,  FALSE,
8018     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
8019   },
8020   {
8021     Yballoon_wB,                        FALSE,  TRUE,
8022     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
8023   },
8024   {
8025     Xgrass,                             TRUE,   FALSE,
8026     EL_EMC_GRASS,                       -1, -1
8027   },
8028   {
8029     Ygrass_nB,                          FALSE,  FALSE,
8030     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
8031   },
8032   {
8033     Ygrass_eB,                          FALSE,  FALSE,
8034     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
8035   },
8036   {
8037     Ygrass_sB,                          FALSE,  FALSE,
8038     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
8039   },
8040   {
8041     Ygrass_wB,                          FALSE,  FALSE,
8042     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
8043   },
8044   {
8045     Xdirt,                              TRUE,   FALSE,
8046     EL_SAND,                            -1, -1
8047   },
8048   {
8049     Ydirt_nB,                           FALSE,  FALSE,
8050     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
8051   },
8052   {
8053     Ydirt_eB,                           FALSE,  FALSE,
8054     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
8055   },
8056   {
8057     Ydirt_sB,                           FALSE,  FALSE,
8058     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
8059   },
8060   {
8061     Ydirt_wB,                           FALSE,  FALSE,
8062     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
8063   },
8064   {
8065     Xacid_ne,                           TRUE,   FALSE,
8066     EL_ACID_POOL_TOPRIGHT,              -1, -1
8067   },
8068   {
8069     Xacid_se,                           TRUE,   FALSE,
8070     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
8071   },
8072   {
8073     Xacid_s,                            TRUE,   FALSE,
8074     EL_ACID_POOL_BOTTOM,                -1, -1
8075   },
8076   {
8077     Xacid_sw,                           TRUE,   FALSE,
8078     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
8079   },
8080   {
8081     Xacid_nw,                           TRUE,   FALSE,
8082     EL_ACID_POOL_TOPLEFT,               -1, -1
8083   },
8084   {
8085     Xacid_1,                            TRUE,   FALSE,
8086     EL_ACID,                            -1, -1
8087   },
8088   {
8089     Xacid_2,                            FALSE,  FALSE,
8090     EL_ACID,                            -1, -1
8091   },
8092   {
8093     Xacid_3,                            FALSE,  FALSE,
8094     EL_ACID,                            -1, -1
8095   },
8096   {
8097     Xacid_4,                            FALSE,  FALSE,
8098     EL_ACID,                            -1, -1
8099   },
8100   {
8101     Xacid_5,                            FALSE,  FALSE,
8102     EL_ACID,                            -1, -1
8103   },
8104   {
8105     Xacid_6,                            FALSE,  FALSE,
8106     EL_ACID,                            -1, -1
8107   },
8108   {
8109     Xacid_7,                            FALSE,  FALSE,
8110     EL_ACID,                            -1, -1
8111   },
8112   {
8113     Xacid_8,                            FALSE,  FALSE,
8114     EL_ACID,                            -1, -1
8115   },
8116   {
8117     Xball_1,                            TRUE,   FALSE,
8118     EL_EMC_MAGIC_BALL,                  -1, -1
8119   },
8120   {
8121     Xball_1B,                           FALSE,  FALSE,
8122     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8123   },
8124   {
8125     Xball_2,                            FALSE,  FALSE,
8126     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8127   },
8128   {
8129     Xball_2B,                           FALSE,  FALSE,
8130     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8131   },
8132   {
8133     Yball_eat,                          FALSE,  FALSE,
8134     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
8135   },
8136   {
8137     Ykey_1_eat,                         FALSE,  FALSE,
8138     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
8139   },
8140   {
8141     Ykey_2_eat,                         FALSE,  FALSE,
8142     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
8143   },
8144   {
8145     Ykey_3_eat,                         FALSE,  FALSE,
8146     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
8147   },
8148   {
8149     Ykey_4_eat,                         FALSE,  FALSE,
8150     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
8151   },
8152   {
8153     Ykey_5_eat,                         FALSE,  FALSE,
8154     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
8155   },
8156   {
8157     Ykey_6_eat,                         FALSE,  FALSE,
8158     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
8159   },
8160   {
8161     Ykey_7_eat,                         FALSE,  FALSE,
8162     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
8163   },
8164   {
8165     Ykey_8_eat,                         FALSE,  FALSE,
8166     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
8167   },
8168   {
8169     Ylenses_eat,                        FALSE,  FALSE,
8170     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
8171   },
8172   {
8173     Ymagnify_eat,                       FALSE,  FALSE,
8174     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
8175   },
8176   {
8177     Ygrass_eat,                         FALSE,  FALSE,
8178     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
8179   },
8180   {
8181     Ydirt_eat,                          FALSE,  FALSE,
8182     EL_SAND,                            ACTION_SNAPPING, -1
8183   },
8184   {
8185     Xgrow_ns,                           TRUE,   FALSE,
8186     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
8187   },
8188   {
8189     Ygrow_ns_eat,                       FALSE,  FALSE,
8190     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
8191   },
8192   {
8193     Xgrow_ew,                           TRUE,   FALSE,
8194     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
8195   },
8196   {
8197     Ygrow_ew_eat,                       FALSE,  FALSE,
8198     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
8199   },
8200   {
8201     Xwonderwall,                        TRUE,   FALSE,
8202     EL_MAGIC_WALL,                      -1, -1
8203   },
8204   {
8205     XwonderwallB,                       FALSE,  FALSE,
8206     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
8207   },
8208   {
8209     Xamoeba_1,                          TRUE,   FALSE,
8210     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8211   },
8212   {
8213     Xamoeba_2,                          FALSE,  FALSE,
8214     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8215   },
8216   {
8217     Xamoeba_3,                          FALSE,  FALSE,
8218     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8219   },
8220   {
8221     Xamoeba_4,                          FALSE,  FALSE,
8222     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8223   },
8224   {
8225     Xamoeba_5,                          TRUE,   FALSE,
8226     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8227   },
8228   {
8229     Xamoeba_6,                          FALSE,  FALSE,
8230     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8231   },
8232   {
8233     Xamoeba_7,                          FALSE,  FALSE,
8234     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8235   },
8236   {
8237     Xamoeba_8,                          FALSE,  FALSE,
8238     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8239   },
8240   {
8241     Xdoor_1,                            TRUE,   FALSE,
8242     EL_EM_GATE_1,                       -1, -1
8243   },
8244   {
8245     Xdoor_2,                            TRUE,   FALSE,
8246     EL_EM_GATE_2,                       -1, -1
8247   },
8248   {
8249     Xdoor_3,                            TRUE,   FALSE,
8250     EL_EM_GATE_3,                       -1, -1
8251   },
8252   {
8253     Xdoor_4,                            TRUE,   FALSE,
8254     EL_EM_GATE_4,                       -1, -1
8255   },
8256   {
8257     Xdoor_5,                            TRUE,   FALSE,
8258     EL_EMC_GATE_5,                      -1, -1
8259   },
8260   {
8261     Xdoor_6,                            TRUE,   FALSE,
8262     EL_EMC_GATE_6,                      -1, -1
8263   },
8264   {
8265     Xdoor_7,                            TRUE,   FALSE,
8266     EL_EMC_GATE_7,                      -1, -1
8267   },
8268   {
8269     Xdoor_8,                            TRUE,   FALSE,
8270     EL_EMC_GATE_8,                      -1, -1
8271   },
8272   {
8273     Xkey_1,                             TRUE,   FALSE,
8274     EL_EM_KEY_1,                        -1, -1
8275   },
8276   {
8277     Xkey_2,                             TRUE,   FALSE,
8278     EL_EM_KEY_2,                        -1, -1
8279   },
8280   {
8281     Xkey_3,                             TRUE,   FALSE,
8282     EL_EM_KEY_3,                        -1, -1
8283   },
8284   {
8285     Xkey_4,                             TRUE,   FALSE,
8286     EL_EM_KEY_4,                        -1, -1
8287   },
8288   {
8289     Xkey_5,                             TRUE,   FALSE,
8290     EL_EMC_KEY_5,                       -1, -1
8291   },
8292   {
8293     Xkey_6,                             TRUE,   FALSE,
8294     EL_EMC_KEY_6,                       -1, -1
8295   },
8296   {
8297     Xkey_7,                             TRUE,   FALSE,
8298     EL_EMC_KEY_7,                       -1, -1
8299   },
8300   {
8301     Xkey_8,                             TRUE,   FALSE,
8302     EL_EMC_KEY_8,                       -1, -1
8303   },
8304   {
8305     Xwind_n,                            TRUE,   FALSE,
8306     EL_BALLOON_SWITCH_UP,               -1, -1
8307   },
8308   {
8309     Xwind_e,                            TRUE,   FALSE,
8310     EL_BALLOON_SWITCH_RIGHT,            -1, -1
8311   },
8312   {
8313     Xwind_s,                            TRUE,   FALSE,
8314     EL_BALLOON_SWITCH_DOWN,             -1, -1
8315   },
8316   {
8317     Xwind_w,                            TRUE,   FALSE,
8318     EL_BALLOON_SWITCH_LEFT,             -1, -1
8319   },
8320   {
8321     Xwind_nesw,                         TRUE,   FALSE,
8322     EL_BALLOON_SWITCH_ANY,              -1, -1
8323   },
8324   {
8325     Xwind_stop,                         TRUE,   FALSE,
8326     EL_BALLOON_SWITCH_NONE,             -1, -1
8327   },
8328   {
8329     Xexit,                              TRUE,   FALSE,
8330     EL_EM_EXIT_CLOSED,                  -1, -1
8331   },
8332   {
8333     Xexit_1,                            TRUE,   FALSE,
8334     EL_EM_EXIT_OPEN,                    -1, -1
8335   },
8336   {
8337     Xexit_2,                            FALSE,  FALSE,
8338     EL_EM_EXIT_OPEN,                    -1, -1
8339   },
8340   {
8341     Xexit_3,                            FALSE,  FALSE,
8342     EL_EM_EXIT_OPEN,                    -1, -1
8343   },
8344   {
8345     Xdynamite,                          TRUE,   FALSE,
8346     EL_EM_DYNAMITE,                     -1, -1
8347   },
8348   {
8349     Ydynamite_eat,                      FALSE,  FALSE,
8350     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
8351   },
8352   {
8353     Xdynamite_1,                        TRUE,   FALSE,
8354     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8355   },
8356   {
8357     Xdynamite_2,                        FALSE,  FALSE,
8358     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8359   },
8360   {
8361     Xdynamite_3,                        FALSE,  FALSE,
8362     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8363   },
8364   {
8365     Xdynamite_4,                        FALSE,  FALSE,
8366     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8367   },
8368   {
8369     Xbumper,                            TRUE,   FALSE,
8370     EL_EMC_SPRING_BUMPER,               -1, -1
8371   },
8372   {
8373     XbumperB,                           FALSE,  FALSE,
8374     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
8375   },
8376   {
8377     Xwheel,                             TRUE,   FALSE,
8378     EL_ROBOT_WHEEL,                     -1, -1
8379   },
8380   {
8381     XwheelB,                            FALSE,  FALSE,
8382     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
8383   },
8384   {
8385     Xswitch,                            TRUE,   FALSE,
8386     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
8387   },
8388   {
8389     XswitchB,                           FALSE,  FALSE,
8390     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
8391   },
8392   {
8393     Xsand,                              TRUE,   FALSE,
8394     EL_QUICKSAND_EMPTY,                 -1, -1
8395   },
8396   {
8397     Xsand_stone,                        TRUE,   FALSE,
8398     EL_QUICKSAND_FULL,                  -1, -1
8399   },
8400   {
8401     Xsand_stonein_1,                    FALSE,  TRUE,
8402     EL_ROCK,                            ACTION_FILLING, -1
8403   },
8404   {
8405     Xsand_stonein_2,                    FALSE,  TRUE,
8406     EL_ROCK,                            ACTION_FILLING, -1
8407   },
8408   {
8409     Xsand_stonein_3,                    FALSE,  TRUE,
8410     EL_ROCK,                            ACTION_FILLING, -1
8411   },
8412   {
8413     Xsand_stonein_4,                    FALSE,  TRUE,
8414     EL_ROCK,                            ACTION_FILLING, -1
8415   },
8416 #if 1
8417   {
8418     Xsand_stonesand_1,                  FALSE,  FALSE,
8419     EL_QUICKSAND_EMPTYING,              -1, -1
8420   },
8421   {
8422     Xsand_stonesand_2,                  FALSE,  FALSE,
8423     EL_QUICKSAND_EMPTYING,              -1, -1
8424   },
8425   {
8426     Xsand_stonesand_3,                  FALSE,  FALSE,
8427     EL_QUICKSAND_EMPTYING,              -1, -1
8428   },
8429   {
8430     Xsand_stonesand_4,                  FALSE,  FALSE,
8431     EL_QUICKSAND_EMPTYING,              -1, -1
8432   },
8433   {
8434     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
8435     EL_QUICKSAND_EMPTYING,              -1, -1
8436   },
8437   {
8438     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
8439     EL_QUICKSAND_EMPTYING,              -1, -1
8440   },
8441 #else
8442   {
8443     Xsand_stonesand_1,                  FALSE,  FALSE,
8444     EL_QUICKSAND_FULL,                  -1, -1
8445   },
8446   {
8447     Xsand_stonesand_2,                  FALSE,  FALSE,
8448     EL_QUICKSAND_FULL,                  -1, -1
8449   },
8450   {
8451     Xsand_stonesand_3,                  FALSE,  FALSE,
8452     EL_QUICKSAND_FULL,                  -1, -1
8453   },
8454   {
8455     Xsand_stonesand_4,                  FALSE,  FALSE,
8456     EL_QUICKSAND_FULL,                  -1, -1
8457   },
8458 #endif
8459   {
8460     Xsand_stoneout_1,                   FALSE,  FALSE,
8461     EL_ROCK,                            ACTION_EMPTYING, -1
8462   },
8463   {
8464     Xsand_stoneout_2,                   FALSE,  FALSE,
8465     EL_ROCK,                            ACTION_EMPTYING, -1
8466   },
8467 #if 1
8468   {
8469     Xsand_sandstone_1,                  FALSE,  FALSE,
8470     EL_QUICKSAND_FILLING,               -1, -1
8471   },
8472   {
8473     Xsand_sandstone_2,                  FALSE,  FALSE,
8474     EL_QUICKSAND_FILLING,               -1, -1
8475   },
8476   {
8477     Xsand_sandstone_3,                  FALSE,  FALSE,
8478     EL_QUICKSAND_FILLING,               -1, -1
8479   },
8480   {
8481     Xsand_sandstone_4,                  FALSE,  FALSE,
8482     EL_QUICKSAND_FILLING,               -1, -1
8483   },
8484 #else
8485   {
8486     Xsand_sandstone_1,                  FALSE,  FALSE,
8487     EL_QUICKSAND_FULL,                  -1, -1
8488   },
8489   {
8490     Xsand_sandstone_2,                  FALSE,  FALSE,
8491     EL_QUICKSAND_FULL,                  -1, -1
8492   },
8493   {
8494     Xsand_sandstone_3,                  FALSE,  FALSE,
8495     EL_QUICKSAND_FULL,                  -1, -1
8496   },
8497   {
8498     Xsand_sandstone_4,                  FALSE,  FALSE,
8499     EL_QUICKSAND_FULL,                  -1, -1
8500   },
8501 #endif
8502   {
8503     Xplant,                             TRUE,   FALSE,
8504     EL_EMC_PLANT,                       -1, -1
8505   },
8506   {
8507     Yplant,                             FALSE,  FALSE,
8508     EL_EMC_PLANT,                       -1, -1
8509   },
8510   {
8511     Xlenses,                            TRUE,   FALSE,
8512     EL_EMC_LENSES,                      -1, -1
8513   },
8514   {
8515     Xmagnify,                           TRUE,   FALSE,
8516     EL_EMC_MAGNIFIER,                   -1, -1
8517   },
8518   {
8519     Xdripper,                           TRUE,   FALSE,
8520     EL_EMC_DRIPPER,                     -1, -1
8521   },
8522   {
8523     XdripperB,                          FALSE,  FALSE,
8524     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
8525   },
8526   {
8527     Xfake_blank,                        TRUE,   FALSE,
8528     EL_INVISIBLE_WALL,                  -1, -1
8529   },
8530   {
8531     Xfake_blankB,                       FALSE,  FALSE,
8532     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
8533   },
8534   {
8535     Xfake_grass,                        TRUE,   FALSE,
8536     EL_EMC_FAKE_GRASS,                  -1, -1
8537   },
8538   {
8539     Xfake_grassB,                       FALSE,  FALSE,
8540     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
8541   },
8542   {
8543     Xfake_door_1,                       TRUE,   FALSE,
8544     EL_EM_GATE_1_GRAY,                  -1, -1
8545   },
8546   {
8547     Xfake_door_2,                       TRUE,   FALSE,
8548     EL_EM_GATE_2_GRAY,                  -1, -1
8549   },
8550   {
8551     Xfake_door_3,                       TRUE,   FALSE,
8552     EL_EM_GATE_3_GRAY,                  -1, -1
8553   },
8554   {
8555     Xfake_door_4,                       TRUE,   FALSE,
8556     EL_EM_GATE_4_GRAY,                  -1, -1
8557   },
8558   {
8559     Xfake_door_5,                       TRUE,   FALSE,
8560     EL_EMC_GATE_5_GRAY,                 -1, -1
8561   },
8562   {
8563     Xfake_door_6,                       TRUE,   FALSE,
8564     EL_EMC_GATE_6_GRAY,                 -1, -1
8565   },
8566   {
8567     Xfake_door_7,                       TRUE,   FALSE,
8568     EL_EMC_GATE_7_GRAY,                 -1, -1
8569   },
8570   {
8571     Xfake_door_8,                       TRUE,   FALSE,
8572     EL_EMC_GATE_8_GRAY,                 -1, -1
8573   },
8574   {
8575     Xfake_acid_1,                       TRUE,   FALSE,
8576     EL_EMC_FAKE_ACID,                   -1, -1
8577   },
8578   {
8579     Xfake_acid_2,                       FALSE,  FALSE,
8580     EL_EMC_FAKE_ACID,                   -1, -1
8581   },
8582   {
8583     Xfake_acid_3,                       FALSE,  FALSE,
8584     EL_EMC_FAKE_ACID,                   -1, -1
8585   },
8586   {
8587     Xfake_acid_4,                       FALSE,  FALSE,
8588     EL_EMC_FAKE_ACID,                   -1, -1
8589   },
8590   {
8591     Xfake_acid_5,                       FALSE,  FALSE,
8592     EL_EMC_FAKE_ACID,                   -1, -1
8593   },
8594   {
8595     Xfake_acid_6,                       FALSE,  FALSE,
8596     EL_EMC_FAKE_ACID,                   -1, -1
8597   },
8598   {
8599     Xfake_acid_7,                       FALSE,  FALSE,
8600     EL_EMC_FAKE_ACID,                   -1, -1
8601   },
8602   {
8603     Xfake_acid_8,                       FALSE,  FALSE,
8604     EL_EMC_FAKE_ACID,                   -1, -1
8605   },
8606   {
8607     Xsteel_1,                           TRUE,   FALSE,
8608     EL_STEELWALL,                       -1, -1
8609   },
8610   {
8611     Xsteel_2,                           TRUE,   FALSE,
8612     EL_EMC_STEELWALL_2,                 -1, -1
8613   },
8614   {
8615     Xsteel_3,                           TRUE,   FALSE,
8616     EL_EMC_STEELWALL_3,                 -1, -1
8617   },
8618   {
8619     Xsteel_4,                           TRUE,   FALSE,
8620     EL_EMC_STEELWALL_4,                 -1, -1
8621   },
8622   {
8623     Xwall_1,                            TRUE,   FALSE,
8624     EL_WALL,                            -1, -1
8625   },
8626   {
8627     Xwall_2,                            TRUE,   FALSE,
8628     EL_EMC_WALL_14,                     -1, -1
8629   },
8630   {
8631     Xwall_3,                            TRUE,   FALSE,
8632     EL_EMC_WALL_15,                     -1, -1
8633   },
8634   {
8635     Xwall_4,                            TRUE,   FALSE,
8636     EL_EMC_WALL_16,                     -1, -1
8637   },
8638   {
8639     Xround_wall_1,                      TRUE,   FALSE,
8640     EL_WALL_SLIPPERY,                   -1, -1
8641   },
8642   {
8643     Xround_wall_2,                      TRUE,   FALSE,
8644     EL_EMC_WALL_SLIPPERY_2,             -1, -1
8645   },
8646   {
8647     Xround_wall_3,                      TRUE,   FALSE,
8648     EL_EMC_WALL_SLIPPERY_3,             -1, -1
8649   },
8650   {
8651     Xround_wall_4,                      TRUE,   FALSE,
8652     EL_EMC_WALL_SLIPPERY_4,             -1, -1
8653   },
8654   {
8655     Xdecor_1,                           TRUE,   FALSE,
8656     EL_EMC_WALL_8,                      -1, -1
8657   },
8658   {
8659     Xdecor_2,                           TRUE,   FALSE,
8660     EL_EMC_WALL_6,                      -1, -1
8661   },
8662   {
8663     Xdecor_3,                           TRUE,   FALSE,
8664     EL_EMC_WALL_4,                      -1, -1
8665   },
8666   {
8667     Xdecor_4,                           TRUE,   FALSE,
8668     EL_EMC_WALL_7,                      -1, -1
8669   },
8670   {
8671     Xdecor_5,                           TRUE,   FALSE,
8672     EL_EMC_WALL_5,                      -1, -1
8673   },
8674   {
8675     Xdecor_6,                           TRUE,   FALSE,
8676     EL_EMC_WALL_9,                      -1, -1
8677   },
8678   {
8679     Xdecor_7,                           TRUE,   FALSE,
8680     EL_EMC_WALL_10,                     -1, -1
8681   },
8682   {
8683     Xdecor_8,                           TRUE,   FALSE,
8684     EL_EMC_WALL_1,                      -1, -1
8685   },
8686   {
8687     Xdecor_9,                           TRUE,   FALSE,
8688     EL_EMC_WALL_2,                      -1, -1
8689   },
8690   {
8691     Xdecor_10,                          TRUE,   FALSE,
8692     EL_EMC_WALL_3,                      -1, -1
8693   },
8694   {
8695     Xdecor_11,                          TRUE,   FALSE,
8696     EL_EMC_WALL_11,                     -1, -1
8697   },
8698   {
8699     Xdecor_12,                          TRUE,   FALSE,
8700     EL_EMC_WALL_12,                     -1, -1
8701   },
8702   {
8703     Xalpha_0,                           TRUE,   FALSE,
8704     EL_CHAR('0'),                       -1, -1
8705   },
8706   {
8707     Xalpha_1,                           TRUE,   FALSE,
8708     EL_CHAR('1'),                       -1, -1
8709   },
8710   {
8711     Xalpha_2,                           TRUE,   FALSE,
8712     EL_CHAR('2'),                       -1, -1
8713   },
8714   {
8715     Xalpha_3,                           TRUE,   FALSE,
8716     EL_CHAR('3'),                       -1, -1
8717   },
8718   {
8719     Xalpha_4,                           TRUE,   FALSE,
8720     EL_CHAR('4'),                       -1, -1
8721   },
8722   {
8723     Xalpha_5,                           TRUE,   FALSE,
8724     EL_CHAR('5'),                       -1, -1
8725   },
8726   {
8727     Xalpha_6,                           TRUE,   FALSE,
8728     EL_CHAR('6'),                       -1, -1
8729   },
8730   {
8731     Xalpha_7,                           TRUE,   FALSE,
8732     EL_CHAR('7'),                       -1, -1
8733   },
8734   {
8735     Xalpha_8,                           TRUE,   FALSE,
8736     EL_CHAR('8'),                       -1, -1
8737   },
8738   {
8739     Xalpha_9,                           TRUE,   FALSE,
8740     EL_CHAR('9'),                       -1, -1
8741   },
8742   {
8743     Xalpha_excla,                       TRUE,   FALSE,
8744     EL_CHAR('!'),                       -1, -1
8745   },
8746   {
8747     Xalpha_quote,                       TRUE,   FALSE,
8748     EL_CHAR('"'),                       -1, -1
8749   },
8750   {
8751     Xalpha_comma,                       TRUE,   FALSE,
8752     EL_CHAR(','),                       -1, -1
8753   },
8754   {
8755     Xalpha_minus,                       TRUE,   FALSE,
8756     EL_CHAR('-'),                       -1, -1
8757   },
8758   {
8759     Xalpha_perio,                       TRUE,   FALSE,
8760     EL_CHAR('.'),                       -1, -1
8761   },
8762   {
8763     Xalpha_colon,                       TRUE,   FALSE,
8764     EL_CHAR(':'),                       -1, -1
8765   },
8766   {
8767     Xalpha_quest,                       TRUE,   FALSE,
8768     EL_CHAR('?'),                       -1, -1
8769   },
8770   {
8771     Xalpha_a,                           TRUE,   FALSE,
8772     EL_CHAR('A'),                       -1, -1
8773   },
8774   {
8775     Xalpha_b,                           TRUE,   FALSE,
8776     EL_CHAR('B'),                       -1, -1
8777   },
8778   {
8779     Xalpha_c,                           TRUE,   FALSE,
8780     EL_CHAR('C'),                       -1, -1
8781   },
8782   {
8783     Xalpha_d,                           TRUE,   FALSE,
8784     EL_CHAR('D'),                       -1, -1
8785   },
8786   {
8787     Xalpha_e,                           TRUE,   FALSE,
8788     EL_CHAR('E'),                       -1, -1
8789   },
8790   {
8791     Xalpha_f,                           TRUE,   FALSE,
8792     EL_CHAR('F'),                       -1, -1
8793   },
8794   {
8795     Xalpha_g,                           TRUE,   FALSE,
8796     EL_CHAR('G'),                       -1, -1
8797   },
8798   {
8799     Xalpha_h,                           TRUE,   FALSE,
8800     EL_CHAR('H'),                       -1, -1
8801   },
8802   {
8803     Xalpha_i,                           TRUE,   FALSE,
8804     EL_CHAR('I'),                       -1, -1
8805   },
8806   {
8807     Xalpha_j,                           TRUE,   FALSE,
8808     EL_CHAR('J'),                       -1, -1
8809   },
8810   {
8811     Xalpha_k,                           TRUE,   FALSE,
8812     EL_CHAR('K'),                       -1, -1
8813   },
8814   {
8815     Xalpha_l,                           TRUE,   FALSE,
8816     EL_CHAR('L'),                       -1, -1
8817   },
8818   {
8819     Xalpha_m,                           TRUE,   FALSE,
8820     EL_CHAR('M'),                       -1, -1
8821   },
8822   {
8823     Xalpha_n,                           TRUE,   FALSE,
8824     EL_CHAR('N'),                       -1, -1
8825   },
8826   {
8827     Xalpha_o,                           TRUE,   FALSE,
8828     EL_CHAR('O'),                       -1, -1
8829   },
8830   {
8831     Xalpha_p,                           TRUE,   FALSE,
8832     EL_CHAR('P'),                       -1, -1
8833   },
8834   {
8835     Xalpha_q,                           TRUE,   FALSE,
8836     EL_CHAR('Q'),                       -1, -1
8837   },
8838   {
8839     Xalpha_r,                           TRUE,   FALSE,
8840     EL_CHAR('R'),                       -1, -1
8841   },
8842   {
8843     Xalpha_s,                           TRUE,   FALSE,
8844     EL_CHAR('S'),                       -1, -1
8845   },
8846   {
8847     Xalpha_t,                           TRUE,   FALSE,
8848     EL_CHAR('T'),                       -1, -1
8849   },
8850   {
8851     Xalpha_u,                           TRUE,   FALSE,
8852     EL_CHAR('U'),                       -1, -1
8853   },
8854   {
8855     Xalpha_v,                           TRUE,   FALSE,
8856     EL_CHAR('V'),                       -1, -1
8857   },
8858   {
8859     Xalpha_w,                           TRUE,   FALSE,
8860     EL_CHAR('W'),                       -1, -1
8861   },
8862   {
8863     Xalpha_x,                           TRUE,   FALSE,
8864     EL_CHAR('X'),                       -1, -1
8865   },
8866   {
8867     Xalpha_y,                           TRUE,   FALSE,
8868     EL_CHAR('Y'),                       -1, -1
8869   },
8870   {
8871     Xalpha_z,                           TRUE,   FALSE,
8872     EL_CHAR('Z'),                       -1, -1
8873   },
8874   {
8875     Xalpha_arrow_e,                     TRUE,   FALSE,
8876     EL_CHAR('>'),                       -1, -1
8877   },
8878   {
8879     Xalpha_arrow_w,                     TRUE,   FALSE,
8880     EL_CHAR('<'),                       -1, -1
8881   },
8882   {
8883     Xalpha_copyr,                       TRUE,   FALSE,
8884     EL_CHAR('©'),                       -1, -1
8885   },
8886
8887   {
8888     Xboom_bug,                          FALSE,  FALSE,
8889     EL_BUG,                             ACTION_EXPLODING, -1
8890   },
8891   {
8892     Xboom_bomb,                         FALSE,  FALSE,
8893     EL_BOMB,                            ACTION_EXPLODING, -1
8894   },
8895   {
8896     Xboom_android,                      FALSE,  FALSE,
8897     EL_EMC_ANDROID,                     ACTION_OTHER, -1
8898   },
8899   {
8900     Xboom_1,                            FALSE,  FALSE,
8901     EL_DEFAULT,                         ACTION_EXPLODING, -1
8902   },
8903   {
8904     Xboom_2,                            FALSE,  FALSE,
8905     EL_DEFAULT,                         ACTION_EXPLODING, -1
8906   },
8907   {
8908     Znormal,                            FALSE,  FALSE,
8909     EL_EMPTY,                           -1, -1
8910   },
8911   {
8912     Zdynamite,                          FALSE,  FALSE,
8913     EL_EMPTY,                           -1, -1
8914   },
8915   {
8916     Zplayer,                            FALSE,  FALSE,
8917     EL_EMPTY,                           -1, -1
8918   },
8919   {
8920     ZBORDER,                            FALSE,  FALSE,
8921     EL_EMPTY,                           -1, -1
8922   },
8923
8924   {
8925     -1,                                 FALSE,  FALSE,
8926     -1,                                 -1, -1
8927   }
8928 };
8929
8930 static struct Mapping_EM_to_RND_player
8931 {
8932   int action_em;
8933   int player_nr;
8934
8935   int element_rnd;
8936   int action;
8937   int direction;
8938 }
8939 em_player_mapping_list[] =
8940 {
8941   {
8942     SPR_walk + 0,                       0,
8943     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
8944   },
8945   {
8946     SPR_walk + 1,                       0,
8947     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
8948   },
8949   {
8950     SPR_walk + 2,                       0,
8951     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
8952   },
8953   {
8954     SPR_walk + 3,                       0,
8955     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
8956   },
8957   {
8958     SPR_push + 0,                       0,
8959     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
8960   },
8961   {
8962     SPR_push + 1,                       0,
8963     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
8964   },
8965   {
8966     SPR_push + 2,                       0,
8967     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
8968   },
8969   {
8970     SPR_push + 3,                       0,
8971     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
8972   },
8973   {
8974     SPR_spray + 0,                      0,
8975     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
8976   },
8977   {
8978     SPR_spray + 1,                      0,
8979     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8980   },
8981   {
8982     SPR_spray + 2,                      0,
8983     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
8984   },
8985   {
8986     SPR_spray + 3,                      0,
8987     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
8988   },
8989   {
8990     SPR_walk + 0,                       1,
8991     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
8992   },
8993   {
8994     SPR_walk + 1,                       1,
8995     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
8996   },
8997   {
8998     SPR_walk + 2,                       1,
8999     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
9000   },
9001   {
9002     SPR_walk + 3,                       1,
9003     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
9004   },
9005   {
9006     SPR_push + 0,                       1,
9007     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
9008   },
9009   {
9010     SPR_push + 1,                       1,
9011     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
9012   },
9013   {
9014     SPR_push + 2,                       1,
9015     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
9016   },
9017   {
9018     SPR_push + 3,                       1,
9019     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
9020   },
9021   {
9022     SPR_spray + 0,                      1,
9023     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
9024   },
9025   {
9026     SPR_spray + 1,                      1,
9027     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9028   },
9029   {
9030     SPR_spray + 2,                      1,
9031     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
9032   },
9033   {
9034     SPR_spray + 3,                      1,
9035     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
9036   },
9037   {
9038     SPR_still,                          0,
9039     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
9040   },
9041   {
9042     SPR_still,                          1,
9043     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
9044   },
9045   {
9046     SPR_walk + 0,                       2,
9047     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
9048   },
9049   {
9050     SPR_walk + 1,                       2,
9051     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
9052   },
9053   {
9054     SPR_walk + 2,                       2,
9055     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
9056   },
9057   {
9058     SPR_walk + 3,                       2,
9059     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
9060   },
9061   {
9062     SPR_push + 0,                       2,
9063     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
9064   },
9065   {
9066     SPR_push + 1,                       2,
9067     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
9068   },
9069   {
9070     SPR_push + 2,                       2,
9071     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
9072   },
9073   {
9074     SPR_push + 3,                       2,
9075     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
9076   },
9077   {
9078     SPR_spray + 0,                      2,
9079     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
9080   },
9081   {
9082     SPR_spray + 1,                      2,
9083     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9084   },
9085   {
9086     SPR_spray + 2,                      2,
9087     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
9088   },
9089   {
9090     SPR_spray + 3,                      2,
9091     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
9092   },
9093   {
9094     SPR_walk + 0,                       3,
9095     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
9096   },
9097   {
9098     SPR_walk + 1,                       3,
9099     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
9100   },
9101   {
9102     SPR_walk + 2,                       3,
9103     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
9104   },
9105   {
9106     SPR_walk + 3,                       3,
9107     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
9108   },
9109   {
9110     SPR_push + 0,                       3,
9111     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
9112   },
9113   {
9114     SPR_push + 1,                       3,
9115     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
9116   },
9117   {
9118     SPR_push + 2,                       3,
9119     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
9120   },
9121   {
9122     SPR_push + 3,                       3,
9123     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
9124   },
9125   {
9126     SPR_spray + 0,                      3,
9127     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
9128   },
9129   {
9130     SPR_spray + 1,                      3,
9131     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9132   },
9133   {
9134     SPR_spray + 2,                      3,
9135     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
9136   },
9137   {
9138     SPR_spray + 3,                      3,
9139     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
9140   },
9141   {
9142     SPR_still,                          2,
9143     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
9144   },
9145   {
9146     SPR_still,                          3,
9147     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
9148   },
9149
9150   {
9151     -1,                                 -1,
9152     -1,                                 -1, -1
9153   }
9154 };
9155
9156 int map_element_RND_to_EM(int element_rnd)
9157 {
9158   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9159   static boolean mapping_initialized = FALSE;
9160
9161   if (!mapping_initialized)
9162   {
9163     int i;
9164
9165     /* return "Xalpha_quest" for all undefined elements in mapping array */
9166     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9167       mapping_RND_to_EM[i] = Xalpha_quest;
9168
9169     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9170       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9171         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9172           em_object_mapping_list[i].element_em;
9173
9174     mapping_initialized = TRUE;
9175   }
9176
9177   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9178     return mapping_RND_to_EM[element_rnd];
9179
9180   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9181
9182   return EL_UNKNOWN;
9183 }
9184
9185 int map_element_EM_to_RND(int element_em)
9186 {
9187   static unsigned short mapping_EM_to_RND[TILE_MAX];
9188   static boolean mapping_initialized = FALSE;
9189
9190   if (!mapping_initialized)
9191   {
9192     int i;
9193
9194     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9195     for (i = 0; i < TILE_MAX; i++)
9196       mapping_EM_to_RND[i] = EL_UNKNOWN;
9197
9198     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9199       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9200         em_object_mapping_list[i].element_rnd;
9201
9202     mapping_initialized = TRUE;
9203   }
9204
9205   if (element_em >= 0 && element_em < TILE_MAX)
9206     return mapping_EM_to_RND[element_em];
9207
9208   Error(ERR_WARN, "invalid EM level element %d", element_em);
9209
9210   return EL_UNKNOWN;
9211 }
9212
9213 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9214 {
9215   struct LevelInfo_EM *level_em = level->native_em_level;
9216   struct LEVEL *lev = level_em->lev;
9217   int i, j;
9218
9219   for (i = 0; i < TILE_MAX; i++)
9220     lev->android_array[i] = Xblank;
9221
9222   for (i = 0; i < level->num_android_clone_elements; i++)
9223   {
9224     int element_rnd = level->android_clone_element[i];
9225     int element_em = map_element_RND_to_EM(element_rnd);
9226
9227     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9228       if (em_object_mapping_list[j].element_rnd == element_rnd)
9229         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9230   }
9231 }
9232
9233 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9234 {
9235   struct LevelInfo_EM *level_em = level->native_em_level;
9236   struct LEVEL *lev = level_em->lev;
9237   int i, j;
9238
9239   level->num_android_clone_elements = 0;
9240
9241   for (i = 0; i < TILE_MAX; i++)
9242   {
9243     int element_em = lev->android_array[i];
9244     int element_rnd;
9245     boolean element_found = FALSE;
9246
9247     if (element_em == Xblank)
9248       continue;
9249
9250     element_rnd = map_element_EM_to_RND(element_em);
9251
9252     for (j = 0; j < level->num_android_clone_elements; j++)
9253       if (level->android_clone_element[j] == element_rnd)
9254         element_found = TRUE;
9255
9256     if (!element_found)
9257     {
9258       level->android_clone_element[level->num_android_clone_elements++] =
9259         element_rnd;
9260
9261       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9262         break;
9263     }
9264   }
9265
9266   if (level->num_android_clone_elements == 0)
9267   {
9268     level->num_android_clone_elements = 1;
9269     level->android_clone_element[0] = EL_EMPTY;
9270   }
9271 }
9272
9273 int map_direction_RND_to_EM(int direction)
9274 {
9275   return (direction == MV_UP    ? 0 :
9276           direction == MV_RIGHT ? 1 :
9277           direction == MV_DOWN  ? 2 :
9278           direction == MV_LEFT  ? 3 :
9279           -1);
9280 }
9281
9282 int map_direction_EM_to_RND(int direction)
9283 {
9284   return (direction == 0 ? MV_UP    :
9285           direction == 1 ? MV_RIGHT :
9286           direction == 2 ? MV_DOWN  :
9287           direction == 3 ? MV_LEFT  :
9288           MV_NONE);
9289 }
9290
9291 int map_element_RND_to_SP(int element_rnd)
9292 {
9293   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
9294
9295   if (element_rnd >= EL_SP_START &&
9296       element_rnd <= EL_SP_END)
9297     element_sp = element_rnd - EL_SP_START;
9298   else if (element_rnd == EL_EMPTY_SPACE)
9299     element_sp = 0x00;
9300   else if (element_rnd == EL_INVISIBLE_WALL)
9301     element_sp = 0x28;
9302
9303   return element_sp;
9304 }
9305
9306 int map_element_SP_to_RND(int element_sp)
9307 {
9308   int element_rnd = EL_UNKNOWN;
9309
9310   if (element_sp >= 0x00 &&
9311       element_sp <= 0x27)
9312     element_rnd = EL_SP_START + element_sp;
9313   else if (element_sp == 0x28)
9314     element_rnd = EL_INVISIBLE_WALL;
9315
9316   return element_rnd;
9317 }
9318
9319 int map_action_SP_to_RND(int action_sp)
9320 {
9321   switch (action_sp)
9322   {
9323     case actActive:             return ACTION_ACTIVE;
9324     case actImpact:             return ACTION_IMPACT;
9325     case actExploding:          return ACTION_EXPLODING;
9326     case actDigging:            return ACTION_DIGGING;
9327     case actSnapping:           return ACTION_SNAPPING;
9328     case actCollecting:         return ACTION_COLLECTING;
9329     case actPassing:            return ACTION_PASSING;
9330     case actPushing:            return ACTION_PUSHING;
9331     case actDropping:           return ACTION_DROPPING;
9332
9333     default:                    return ACTION_DEFAULT;
9334   }
9335 }
9336
9337 int get_next_element(int element)
9338 {
9339   switch (element)
9340   {
9341     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
9342     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
9343     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
9344     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
9345     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
9346     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
9347     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
9348     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
9349     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
9350     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
9351     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
9352
9353     default:                            return element;
9354   }
9355 }
9356
9357 #if 0
9358 int el_act_dir2img(int element, int action, int direction)
9359 {
9360   element = GFX_ELEMENT(element);
9361
9362   if (direction == MV_NONE)
9363     return element_info[element].graphic[action];
9364
9365   direction = MV_DIR_TO_BIT(direction);
9366
9367   return element_info[element].direction_graphic[action][direction];
9368 }
9369 #else
9370 int el_act_dir2img(int element, int action, int direction)
9371 {
9372   element = GFX_ELEMENT(element);
9373   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9374
9375   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9376   return element_info[element].direction_graphic[action][direction];
9377 }
9378 #endif
9379
9380 #if 0
9381 static int el_act_dir2crm(int element, int action, int direction)
9382 {
9383   element = GFX_ELEMENT(element);
9384
9385   if (direction == MV_NONE)
9386     return element_info[element].crumbled[action];
9387
9388   direction = MV_DIR_TO_BIT(direction);
9389
9390   return element_info[element].direction_crumbled[action][direction];
9391 }
9392 #else
9393 static int el_act_dir2crm(int element, int action, int direction)
9394 {
9395   element = GFX_ELEMENT(element);
9396   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9397
9398   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9399   return element_info[element].direction_crumbled[action][direction];
9400 }
9401 #endif
9402
9403 int el_act2img(int element, int action)
9404 {
9405   element = GFX_ELEMENT(element);
9406
9407   return element_info[element].graphic[action];
9408 }
9409
9410 int el_act2crm(int element, int action)
9411 {
9412   element = GFX_ELEMENT(element);
9413
9414   return element_info[element].crumbled[action];
9415 }
9416
9417 int el_dir2img(int element, int direction)
9418 {
9419   element = GFX_ELEMENT(element);
9420
9421   return el_act_dir2img(element, ACTION_DEFAULT, direction);
9422 }
9423
9424 int el2baseimg(int element)
9425 {
9426   return element_info[element].graphic[ACTION_DEFAULT];
9427 }
9428
9429 int el2img(int element)
9430 {
9431   element = GFX_ELEMENT(element);
9432
9433   return element_info[element].graphic[ACTION_DEFAULT];
9434 }
9435
9436 int el2edimg(int element)
9437 {
9438   element = GFX_ELEMENT(element);
9439
9440   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9441 }
9442
9443 int el2preimg(int element)
9444 {
9445   element = GFX_ELEMENT(element);
9446
9447   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9448 }
9449
9450 int el2panelimg(int element)
9451 {
9452   element = GFX_ELEMENT(element);
9453
9454   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9455 }
9456
9457 int font2baseimg(int font_nr)
9458 {
9459   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9460 }
9461
9462 int getBeltNrFromBeltElement(int element)
9463 {
9464   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9465           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9466           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9467 }
9468
9469 int getBeltNrFromBeltActiveElement(int element)
9470 {
9471   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9472           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9473           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9474 }
9475
9476 int getBeltNrFromBeltSwitchElement(int element)
9477 {
9478   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9479           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9480           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9481 }
9482
9483 int getBeltDirNrFromBeltElement(int element)
9484 {
9485   static int belt_base_element[4] =
9486   {
9487     EL_CONVEYOR_BELT_1_LEFT,
9488     EL_CONVEYOR_BELT_2_LEFT,
9489     EL_CONVEYOR_BELT_3_LEFT,
9490     EL_CONVEYOR_BELT_4_LEFT
9491   };
9492
9493   int belt_nr = getBeltNrFromBeltElement(element);
9494   int belt_dir_nr = element - belt_base_element[belt_nr];
9495
9496   return (belt_dir_nr % 3);
9497 }
9498
9499 int getBeltDirNrFromBeltSwitchElement(int element)
9500 {
9501   static int belt_base_element[4] =
9502   {
9503     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9504     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9505     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9506     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9507   };
9508
9509   int belt_nr = getBeltNrFromBeltSwitchElement(element);
9510   int belt_dir_nr = element - belt_base_element[belt_nr];
9511
9512   return (belt_dir_nr % 3);
9513 }
9514
9515 int getBeltDirFromBeltElement(int element)
9516 {
9517   static int belt_move_dir[3] =
9518   {
9519     MV_LEFT,
9520     MV_NONE,
9521     MV_RIGHT
9522   };
9523
9524   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9525
9526   return belt_move_dir[belt_dir_nr];
9527 }
9528
9529 int getBeltDirFromBeltSwitchElement(int element)
9530 {
9531   static int belt_move_dir[3] =
9532   {
9533     MV_LEFT,
9534     MV_NONE,
9535     MV_RIGHT
9536   };
9537
9538   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9539
9540   return belt_move_dir[belt_dir_nr];
9541 }
9542
9543 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9544 {
9545   static int belt_base_element[4] =
9546   {
9547     EL_CONVEYOR_BELT_1_LEFT,
9548     EL_CONVEYOR_BELT_2_LEFT,
9549     EL_CONVEYOR_BELT_3_LEFT,
9550     EL_CONVEYOR_BELT_4_LEFT
9551   };
9552
9553   return belt_base_element[belt_nr] + belt_dir_nr;
9554 }
9555
9556 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9557 {
9558   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9559
9560   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9561 }
9562
9563 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9564 {
9565   static int belt_base_element[4] =
9566   {
9567     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9568     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9569     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9570     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9571   };
9572
9573   return belt_base_element[belt_nr] + belt_dir_nr;
9574 }
9575
9576 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9577 {
9578   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9579
9580   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9581 }
9582
9583 #if 1
9584 boolean getTeamMode_EM()
9585 {
9586   return game.team_mode;
9587 }
9588 #else
9589 int getNumActivePlayers_EM()
9590 {
9591 #if 1
9592   int num_players = 0;
9593   int i;
9594
9595   if (!tape.playing)
9596     return (setup.team_mode ? MAX_PLAYERS : 1);
9597
9598   for (i = 0; i < MAX_PLAYERS; i++)
9599     if (tape.player_participates[i])
9600       num_players++;
9601
9602   return (num_players > 1 ? MAX_PLAYERS : 1);
9603
9604 #else
9605
9606   int num_players = 0;
9607   int i;
9608
9609   /* when recording game, activate all connected players */
9610   if (!tape.playing)
9611     return -1;
9612
9613   for (i = 0; i < MAX_PLAYERS; i++)
9614     if (tape.player_participates[i])
9615       num_players++;
9616
9617   return num_players;
9618 #endif
9619 }
9620 #endif
9621
9622 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9623 {
9624   int game_frame_delay_value;
9625
9626   game_frame_delay_value =
9627     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9628      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9629      GameFrameDelay);
9630
9631   if (tape.playing && tape.warp_forward && !tape.pausing)
9632     game_frame_delay_value = 0;
9633
9634   return game_frame_delay_value;
9635 }
9636
9637 unsigned int InitRND(int seed)
9638 {
9639   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9640     return InitEngineRandom_EM(seed);
9641   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9642     return InitEngineRandom_SP(seed);
9643   else
9644     return InitEngineRandom_RND(seed);
9645 }
9646
9647 #if 1
9648 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9649 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9650 #endif
9651
9652 inline static int get_effective_element_EM(int tile, int frame_em)
9653 {
9654   int element             = object_mapping[tile].element_rnd;
9655   int action              = object_mapping[tile].action;
9656   boolean is_backside     = object_mapping[tile].is_backside;
9657   boolean action_removing = (action == ACTION_DIGGING ||
9658                              action == ACTION_SNAPPING ||
9659                              action == ACTION_COLLECTING);
9660
9661   if (frame_em < 7)
9662   {
9663     switch (tile)
9664     {
9665       case Yacid_splash_eB:
9666       case Yacid_splash_wB:
9667         return (frame_em > 5 ? EL_EMPTY : element);
9668
9669 #if 0
9670         /* !!! FIX !!! */
9671       case Ydiamond_stone:
9672         //  if (!game.use_native_emc_graphics_engine)
9673         return EL_ROCK;
9674 #endif
9675
9676       default:
9677         return element;
9678     }
9679   }
9680   else  /* frame_em == 7 */
9681   {
9682     switch (tile)
9683     {
9684       case Yacid_splash_eB:
9685       case Yacid_splash_wB:
9686         return EL_EMPTY;
9687
9688       case Yemerald_stone:
9689         return EL_EMERALD;
9690
9691       case Ydiamond_stone:
9692         return EL_ROCK;
9693
9694       case Xdrip_stretch:
9695       case Xdrip_stretchB:
9696       case Ydrip_s1:
9697       case Ydrip_s1B:
9698       case Xball_1B:
9699       case Xball_2:
9700       case Xball_2B:
9701       case Yball_eat:
9702       case Ykey_1_eat:
9703       case Ykey_2_eat:
9704       case Ykey_3_eat:
9705       case Ykey_4_eat:
9706       case Ykey_5_eat:
9707       case Ykey_6_eat:
9708       case Ykey_7_eat:
9709       case Ykey_8_eat:
9710       case Ylenses_eat:
9711       case Ymagnify_eat:
9712       case Ygrass_eat:
9713       case Ydirt_eat:
9714       case Xsand_stonein_1:
9715       case Xsand_stonein_2:
9716       case Xsand_stonein_3:
9717       case Xsand_stonein_4:
9718         return element;
9719
9720       default:
9721         return (is_backside || action_removing ? EL_EMPTY : element);
9722     }
9723   }
9724 }
9725
9726 inline static boolean check_linear_animation_EM(int tile)
9727 {
9728   switch (tile)
9729   {
9730     case Xsand_stonesand_1:
9731     case Xsand_stonesand_quickout_1:
9732     case Xsand_sandstone_1:
9733     case Xsand_stonein_1:
9734     case Xsand_stoneout_1:
9735     case Xboom_1:
9736     case Xdynamite_1:
9737     case Ybug_w_n:
9738     case Ybug_n_e:
9739     case Ybug_e_s:
9740     case Ybug_s_w:
9741     case Ybug_e_n:
9742     case Ybug_s_e:
9743     case Ybug_w_s:
9744     case Ybug_n_w:
9745     case Ytank_w_n:
9746     case Ytank_n_e:
9747     case Ytank_e_s:
9748     case Ytank_s_w:
9749     case Ytank_e_n:
9750     case Ytank_s_e:
9751     case Ytank_w_s:
9752     case Ytank_n_w:
9753 #if 1
9754     case Yacid_splash_eB:
9755     case Yacid_splash_wB:
9756     case Yemerald_stone:
9757 #endif
9758       return TRUE;
9759   }
9760
9761   return FALSE;
9762 }
9763
9764 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9765                                             boolean has_crumbled_graphics,
9766                                             int crumbled, int sync_frame)
9767 {
9768   /* if element can be crumbled, but certain action graphics are just empty
9769      space (like instantly snapping sand to empty space in 1 frame), do not
9770      treat these empty space graphics as crumbled graphics in EMC engine */
9771   if (crumbled == IMG_EMPTY_SPACE)
9772     has_crumbled_graphics = FALSE;
9773
9774   if (has_crumbled_graphics)
9775   {
9776     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9777     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9778                                            g_crumbled->anim_delay,
9779                                            g_crumbled->anim_mode,
9780                                            g_crumbled->anim_start_frame,
9781                                            sync_frame);
9782
9783     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9784                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9785
9786     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9787
9788     g_em->has_crumbled_graphics = TRUE;
9789   }
9790   else
9791   {
9792     g_em->crumbled_bitmap = NULL;
9793     g_em->crumbled_src_x = 0;
9794     g_em->crumbled_src_y = 0;
9795     g_em->crumbled_border_size = 0;
9796
9797     g_em->has_crumbled_graphics = FALSE;
9798   }
9799 }
9800
9801 void ResetGfxAnimation_EM(int x, int y, int tile)
9802 {
9803   GfxFrame[x][y] = 0;
9804 }
9805
9806 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9807                         int tile, int frame_em, int x, int y)
9808 {
9809   int action = object_mapping[tile].action;
9810 #if 1
9811   int direction = object_mapping[tile].direction;
9812   int effective_element = get_effective_element_EM(tile, frame_em);
9813   int graphic = (direction == MV_NONE ?
9814                  el_act2img(effective_element, action) :
9815                  el_act_dir2img(effective_element, action, direction));
9816   struct GraphicInfo *g = &graphic_info[graphic];
9817   int sync_frame;
9818 #endif
9819   boolean action_removing = (action == ACTION_DIGGING ||
9820                              action == ACTION_SNAPPING ||
9821                              action == ACTION_COLLECTING);
9822   boolean action_moving   = (action == ACTION_FALLING ||
9823                              action == ACTION_MOVING ||
9824                              action == ACTION_PUSHING ||
9825                              action == ACTION_EATING ||
9826                              action == ACTION_FILLING ||
9827                              action == ACTION_EMPTYING);
9828   boolean action_falling  = (action == ACTION_FALLING ||
9829                              action == ACTION_FILLING ||
9830                              action == ACTION_EMPTYING);
9831
9832   /* special case: graphic uses "2nd movement tile" and has defined
9833      7 frames for movement animation (or less) => use default graphic
9834      for last (8th) frame which ends the movement animation */
9835   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9836   {
9837     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
9838     graphic = (direction == MV_NONE ?
9839                el_act2img(effective_element, action) :
9840                el_act_dir2img(effective_element, action, direction));
9841
9842     g = &graphic_info[graphic];
9843   }
9844
9845 #if 0
9846   if (tile == Xsand_stonesand_1 ||
9847       tile == Xsand_stonesand_2 ||
9848       tile == Xsand_stonesand_3 ||
9849       tile == Xsand_stonesand_4)
9850     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9851 #endif
9852
9853 #if 1
9854   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9855   {
9856     GfxFrame[x][y] = 0;
9857
9858     // printf("::: resetting... [%d]\n", tile);
9859   }
9860 #else
9861   if (action_removing || check_linear_animation_EM(tile))
9862   {
9863     GfxFrame[x][y] = frame_em;
9864
9865     // printf("::: resetting... [%d]\n", tile);
9866   }
9867 #endif
9868   else if (action_moving)
9869   {
9870     boolean is_backside = object_mapping[tile].is_backside;
9871
9872     if (is_backside)
9873     {
9874       int direction = object_mapping[tile].direction;
9875       int move_dir = (action_falling ? MV_DOWN : direction);
9876
9877       GfxFrame[x][y]++;
9878
9879 #if 1
9880       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9881       if (g->double_movement && frame_em == 0)
9882       {
9883         GfxFrame[x][y] = 0;
9884
9885         // printf("::: resetting... [%d]\n", tile);
9886       }
9887 #endif
9888
9889       if (move_dir == MV_LEFT)
9890         GfxFrame[x - 1][y] = GfxFrame[x][y];
9891       else if (move_dir == MV_RIGHT)
9892         GfxFrame[x + 1][y] = GfxFrame[x][y];
9893       else if (move_dir == MV_UP)
9894         GfxFrame[x][y - 1] = GfxFrame[x][y];
9895       else if (move_dir == MV_DOWN)
9896         GfxFrame[x][y + 1] = GfxFrame[x][y];
9897     }
9898   }
9899   else
9900   {
9901     GfxFrame[x][y]++;
9902
9903     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9904     if (tile == Xsand_stonesand_quickout_1 ||
9905         tile == Xsand_stonesand_quickout_2)
9906       GfxFrame[x][y]++;
9907   }
9908
9909 #if 0
9910   if (tile == Xsand_stonesand_1 ||
9911       tile == Xsand_stonesand_2 ||
9912       tile == Xsand_stonesand_3 ||
9913       tile == Xsand_stonesand_4)
9914     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9915 #endif
9916
9917 #if 1
9918   if (graphic_info[graphic].anim_global_sync)
9919     sync_frame = FrameCounter;
9920   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9921     sync_frame = GfxFrame[x][y];
9922   else
9923     sync_frame = 0;     /* playfield border (pseudo steel) */
9924
9925   SetRandomAnimationValue(x, y);
9926
9927   int frame = getAnimationFrame(g->anim_frames,
9928                                 g->anim_delay,
9929                                 g->anim_mode,
9930                                 g->anim_start_frame,
9931                                 sync_frame);
9932
9933   g_em->unique_identifier =
9934     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9935 #endif
9936 }
9937
9938 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9939                                   int tile, int frame_em, int x, int y)
9940 {
9941   int action = object_mapping[tile].action;
9942   int direction = object_mapping[tile].direction;
9943   boolean is_backside = object_mapping[tile].is_backside;
9944   int effective_element = get_effective_element_EM(tile, frame_em);
9945 #if 1
9946   int effective_action = action;
9947 #else
9948   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9949 #endif
9950   int graphic = (direction == MV_NONE ?
9951                  el_act2img(effective_element, effective_action) :
9952                  el_act_dir2img(effective_element, effective_action,
9953                                 direction));
9954   int crumbled = (direction == MV_NONE ?
9955                   el_act2crm(effective_element, effective_action) :
9956                   el_act_dir2crm(effective_element, effective_action,
9957                                  direction));
9958   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9959   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9960   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9961   struct GraphicInfo *g = &graphic_info[graphic];
9962 #if 0
9963   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9964 #endif
9965   int sync_frame;
9966
9967   /* special case: graphic uses "2nd movement tile" and has defined
9968      7 frames for movement animation (or less) => use default graphic
9969      for last (8th) frame which ends the movement animation */
9970   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9971   {
9972     effective_action = ACTION_DEFAULT;
9973     graphic = (direction == MV_NONE ?
9974                el_act2img(effective_element, effective_action) :
9975                el_act_dir2img(effective_element, effective_action,
9976                               direction));
9977     crumbled = (direction == MV_NONE ?
9978                 el_act2crm(effective_element, effective_action) :
9979                 el_act_dir2crm(effective_element, effective_action,
9980                                direction));
9981
9982     g = &graphic_info[graphic];
9983   }
9984
9985 #if 0
9986   if (frame_em == 7)
9987     return;
9988 #endif
9989
9990
9991 #if 0
9992   if (frame_em == 0)    /* reset animation frame for certain elements */
9993   {
9994     if (check_linear_animation_EM(tile))
9995       GfxFrame[x][y] = 0;
9996   }
9997 #endif
9998
9999   if (graphic_info[graphic].anim_global_sync)
10000     sync_frame = FrameCounter;
10001   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10002     sync_frame = GfxFrame[x][y];
10003   else
10004     sync_frame = 0;     /* playfield border (pseudo steel) */
10005
10006   SetRandomAnimationValue(x, y);
10007
10008 #if 0
10009   int i = tile;
10010   int j = frame_em;
10011   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10012                         i == Xdrip_stretchB ? 7 :
10013                         i == Ydrip_s2 ? j + 8 :
10014                         i == Ydrip_s2B ? j + 8 :
10015                         i == Xacid_1 ? 0 :
10016                         i == Xacid_2 ? 10 :
10017                         i == Xacid_3 ? 20 :
10018                         i == Xacid_4 ? 30 :
10019                         i == Xacid_5 ? 40 :
10020                         i == Xacid_6 ? 50 :
10021                         i == Xacid_7 ? 60 :
10022                         i == Xacid_8 ? 70 :
10023                         i == Xfake_acid_1 ? 0 :
10024                         i == Xfake_acid_2 ? 10 :
10025                         i == Xfake_acid_3 ? 20 :
10026                         i == Xfake_acid_4 ? 30 :
10027                         i == Xfake_acid_5 ? 40 :
10028                         i == Xfake_acid_6 ? 50 :
10029                         i == Xfake_acid_7 ? 60 :
10030                         i == Xfake_acid_8 ? 70 :
10031                         i == Xball_2 ? 7 :
10032                         i == Xball_2B ? j + 8 :
10033                         i == Yball_eat ? j + 1 :
10034                         i == Ykey_1_eat ? j + 1 :
10035                         i == Ykey_2_eat ? j + 1 :
10036                         i == Ykey_3_eat ? j + 1 :
10037                         i == Ykey_4_eat ? j + 1 :
10038                         i == Ykey_5_eat ? j + 1 :
10039                         i == Ykey_6_eat ? j + 1 :
10040                         i == Ykey_7_eat ? j + 1 :
10041                         i == Ykey_8_eat ? j + 1 :
10042                         i == Ylenses_eat ? j + 1 :
10043                         i == Ymagnify_eat ? j + 1 :
10044                         i == Ygrass_eat ? j + 1 :
10045                         i == Ydirt_eat ? j + 1 :
10046                         i == Xamoeba_1 ? 0 :
10047                         i == Xamoeba_2 ? 1 :
10048                         i == Xamoeba_3 ? 2 :
10049                         i == Xamoeba_4 ? 3 :
10050                         i == Xamoeba_5 ? 0 :
10051                         i == Xamoeba_6 ? 1 :
10052                         i == Xamoeba_7 ? 2 :
10053                         i == Xamoeba_8 ? 3 :
10054                         i == Xexit_2 ? j + 8 :
10055                         i == Xexit_3 ? j + 16 :
10056                         i == Xdynamite_1 ? 0 :
10057                         i == Xdynamite_2 ? 8 :
10058                         i == Xdynamite_3 ? 16 :
10059                         i == Xdynamite_4 ? 24 :
10060                         i == Xsand_stonein_1 ? j + 1 :
10061                         i == Xsand_stonein_2 ? j + 9 :
10062                         i == Xsand_stonein_3 ? j + 17 :
10063                         i == Xsand_stonein_4 ? j + 25 :
10064                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10065                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10066                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10067                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10068                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10069                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10070                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10071                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10072                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10073                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10074                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10075                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10076                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10077                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10078                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10079                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10080                         i == Xboom_bug && j == 1 ? 2 :
10081                         i == Xboom_bug && j == 2 ? 2 :
10082                         i == Xboom_bug && j == 3 ? 4 :
10083                         i == Xboom_bug && j == 4 ? 4 :
10084                         i == Xboom_bug && j == 5 ? 2 :
10085                         i == Xboom_bug && j == 6 ? 2 :
10086                         i == Xboom_bug && j == 7 ? 0 :
10087                         i == Xboom_bomb && j == 1 ? 2 :
10088                         i == Xboom_bomb && j == 2 ? 2 :
10089                         i == Xboom_bomb && j == 3 ? 4 :
10090                         i == Xboom_bomb && j == 4 ? 4 :
10091                         i == Xboom_bomb && j == 5 ? 2 :
10092                         i == Xboom_bomb && j == 6 ? 2 :
10093                         i == Xboom_bomb && j == 7 ? 0 :
10094                         i == Xboom_android && j == 7 ? 6 :
10095                         i == Xboom_1 && j == 1 ? 2 :
10096                         i == Xboom_1 && j == 2 ? 2 :
10097                         i == Xboom_1 && j == 3 ? 4 :
10098                         i == Xboom_1 && j == 4 ? 4 :
10099                         i == Xboom_1 && j == 5 ? 6 :
10100                         i == Xboom_1 && j == 6 ? 6 :
10101                         i == Xboom_1 && j == 7 ? 8 :
10102                         i == Xboom_2 && j == 0 ? 8 :
10103                         i == Xboom_2 && j == 1 ? 8 :
10104                         i == Xboom_2 && j == 2 ? 10 :
10105                         i == Xboom_2 && j == 3 ? 10 :
10106                         i == Xboom_2 && j == 4 ? 10 :
10107                         i == Xboom_2 && j == 5 ? 12 :
10108                         i == Xboom_2 && j == 6 ? 12 :
10109                         i == Xboom_2 && j == 7 ? 12 :
10110 #if 0
10111                         special_animation && j == 4 ? 3 :
10112                         effective_action != action ? 0 :
10113 #endif
10114                         j);
10115 #endif
10116
10117 #if 0
10118   int xxx_effective_action;
10119   int xxx_has_action_graphics;
10120
10121   {
10122     int element = object_mapping[i].element_rnd;
10123     int action = object_mapping[i].action;
10124     int direction = object_mapping[i].direction;
10125     boolean is_backside = object_mapping[i].is_backside;
10126 #if 0
10127     boolean action_removing = (action == ACTION_DIGGING ||
10128                                action == ACTION_SNAPPING ||
10129                                action == ACTION_COLLECTING);
10130 #endif
10131     boolean action_exploding = ((action == ACTION_EXPLODING ||
10132                                  action == ACTION_SMASHED_BY_ROCK ||
10133                                  action == ACTION_SMASHED_BY_SPRING) &&
10134                                 element != EL_DIAMOND);
10135     boolean action_active = (action == ACTION_ACTIVE);
10136     boolean action_other = (action == ACTION_OTHER);
10137
10138     {
10139 #if 1
10140       int effective_element = get_effective_element_EM(i, j);
10141 #else
10142       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10143                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10144                                j < 7 ? element :
10145                                i == Xdrip_stretch ? element :
10146                                i == Xdrip_stretchB ? element :
10147                                i == Ydrip_s1 ? element :
10148                                i == Ydrip_s1B ? element :
10149                                i == Xball_1B ? element :
10150                                i == Xball_2 ? element :
10151                                i == Xball_2B ? element :
10152                                i == Yball_eat ? element :
10153                                i == Ykey_1_eat ? element :
10154                                i == Ykey_2_eat ? element :
10155                                i == Ykey_3_eat ? element :
10156                                i == Ykey_4_eat ? element :
10157                                i == Ykey_5_eat ? element :
10158                                i == Ykey_6_eat ? element :
10159                                i == Ykey_7_eat ? element :
10160                                i == Ykey_8_eat ? element :
10161                                i == Ylenses_eat ? element :
10162                                i == Ymagnify_eat ? element :
10163                                i == Ygrass_eat ? element :
10164                                i == Ydirt_eat ? element :
10165                                i == Yemerald_stone ? EL_EMERALD :
10166                                i == Ydiamond_stone ? EL_ROCK :
10167                                i == Xsand_stonein_1 ? element :
10168                                i == Xsand_stonein_2 ? element :
10169                                i == Xsand_stonein_3 ? element :
10170                                i == Xsand_stonein_4 ? element :
10171                                is_backside ? EL_EMPTY :
10172                                action_removing ? EL_EMPTY :
10173                                element);
10174 #endif
10175       int effective_action = (j < 7 ? action :
10176                               i == Xdrip_stretch ? action :
10177                               i == Xdrip_stretchB ? action :
10178                               i == Ydrip_s1 ? action :
10179                               i == Ydrip_s1B ? action :
10180                               i == Xball_1B ? action :
10181                               i == Xball_2 ? action :
10182                               i == Xball_2B ? action :
10183                               i == Yball_eat ? action :
10184                               i == Ykey_1_eat ? action :
10185                               i == Ykey_2_eat ? action :
10186                               i == Ykey_3_eat ? action :
10187                               i == Ykey_4_eat ? action :
10188                               i == Ykey_5_eat ? action :
10189                               i == Ykey_6_eat ? action :
10190                               i == Ykey_7_eat ? action :
10191                               i == Ykey_8_eat ? action :
10192                               i == Ylenses_eat ? action :
10193                               i == Ymagnify_eat ? action :
10194                               i == Ygrass_eat ? action :
10195                               i == Ydirt_eat ? action :
10196                               i == Xsand_stonein_1 ? action :
10197                               i == Xsand_stonein_2 ? action :
10198                               i == Xsand_stonein_3 ? action :
10199                               i == Xsand_stonein_4 ? action :
10200                               i == Xsand_stoneout_1 ? action :
10201                               i == Xsand_stoneout_2 ? action :
10202                               i == Xboom_android ? ACTION_EXPLODING :
10203                               action_exploding ? ACTION_EXPLODING :
10204                               action_active ? action :
10205                               action_other ? action :
10206                               ACTION_DEFAULT);
10207       int graphic = (el_act_dir2img(effective_element, effective_action,
10208                                     direction));
10209       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10210                                      direction));
10211       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10212       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10213       boolean has_action_graphics = (graphic != base_graphic);
10214       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10215       struct GraphicInfo *g = &graphic_info[graphic];
10216 #if 0
10217       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10218 #endif
10219       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10220       Bitmap *src_bitmap;
10221       int src_x, src_y;
10222       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10223       boolean special_animation = (action != ACTION_DEFAULT &&
10224                                    g->anim_frames == 3 &&
10225                                    g->anim_delay == 2 &&
10226                                    g->anim_mode & ANIM_LINEAR);
10227       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10228                         i == Xdrip_stretchB ? 7 :
10229                         i == Ydrip_s2 ? j + 8 :
10230                         i == Ydrip_s2B ? j + 8 :
10231                         i == Xacid_1 ? 0 :
10232                         i == Xacid_2 ? 10 :
10233                         i == Xacid_3 ? 20 :
10234                         i == Xacid_4 ? 30 :
10235                         i == Xacid_5 ? 40 :
10236                         i == Xacid_6 ? 50 :
10237                         i == Xacid_7 ? 60 :
10238                         i == Xacid_8 ? 70 :
10239                         i == Xfake_acid_1 ? 0 :
10240                         i == Xfake_acid_2 ? 10 :
10241                         i == Xfake_acid_3 ? 20 :
10242                         i == Xfake_acid_4 ? 30 :
10243                         i == Xfake_acid_5 ? 40 :
10244                         i == Xfake_acid_6 ? 50 :
10245                         i == Xfake_acid_7 ? 60 :
10246                         i == Xfake_acid_8 ? 70 :
10247                         i == Xball_2 ? 7 :
10248                         i == Xball_2B ? j + 8 :
10249                         i == Yball_eat ? j + 1 :
10250                         i == Ykey_1_eat ? j + 1 :
10251                         i == Ykey_2_eat ? j + 1 :
10252                         i == Ykey_3_eat ? j + 1 :
10253                         i == Ykey_4_eat ? j + 1 :
10254                         i == Ykey_5_eat ? j + 1 :
10255                         i == Ykey_6_eat ? j + 1 :
10256                         i == Ykey_7_eat ? j + 1 :
10257                         i == Ykey_8_eat ? j + 1 :
10258                         i == Ylenses_eat ? j + 1 :
10259                         i == Ymagnify_eat ? j + 1 :
10260                         i == Ygrass_eat ? j + 1 :
10261                         i == Ydirt_eat ? j + 1 :
10262                         i == Xamoeba_1 ? 0 :
10263                         i == Xamoeba_2 ? 1 :
10264                         i == Xamoeba_3 ? 2 :
10265                         i == Xamoeba_4 ? 3 :
10266                         i == Xamoeba_5 ? 0 :
10267                         i == Xamoeba_6 ? 1 :
10268                         i == Xamoeba_7 ? 2 :
10269                         i == Xamoeba_8 ? 3 :
10270                         i == Xexit_2 ? j + 8 :
10271                         i == Xexit_3 ? j + 16 :
10272                         i == Xdynamite_1 ? 0 :
10273                         i == Xdynamite_2 ? 8 :
10274                         i == Xdynamite_3 ? 16 :
10275                         i == Xdynamite_4 ? 24 :
10276                         i == Xsand_stonein_1 ? j + 1 :
10277                         i == Xsand_stonein_2 ? j + 9 :
10278                         i == Xsand_stonein_3 ? j + 17 :
10279                         i == Xsand_stonein_4 ? j + 25 :
10280                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10281                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10282                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10283                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10284                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10285                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10286                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10287                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10288                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10289                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10290                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10291                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10292                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10293                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10294                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10295                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10296                         i == Xboom_bug && j == 1 ? 2 :
10297                         i == Xboom_bug && j == 2 ? 2 :
10298                         i == Xboom_bug && j == 3 ? 4 :
10299                         i == Xboom_bug && j == 4 ? 4 :
10300                         i == Xboom_bug && j == 5 ? 2 :
10301                         i == Xboom_bug && j == 6 ? 2 :
10302                         i == Xboom_bug && j == 7 ? 0 :
10303                         i == Xboom_bomb && j == 1 ? 2 :
10304                         i == Xboom_bomb && j == 2 ? 2 :
10305                         i == Xboom_bomb && j == 3 ? 4 :
10306                         i == Xboom_bomb && j == 4 ? 4 :
10307                         i == Xboom_bomb && j == 5 ? 2 :
10308                         i == Xboom_bomb && j == 6 ? 2 :
10309                         i == Xboom_bomb && j == 7 ? 0 :
10310                         i == Xboom_android && j == 7 ? 6 :
10311                         i == Xboom_1 && j == 1 ? 2 :
10312                         i == Xboom_1 && j == 2 ? 2 :
10313                         i == Xboom_1 && j == 3 ? 4 :
10314                         i == Xboom_1 && j == 4 ? 4 :
10315                         i == Xboom_1 && j == 5 ? 6 :
10316                         i == Xboom_1 && j == 6 ? 6 :
10317                         i == Xboom_1 && j == 7 ? 8 :
10318                         i == Xboom_2 && j == 0 ? 8 :
10319                         i == Xboom_2 && j == 1 ? 8 :
10320                         i == Xboom_2 && j == 2 ? 10 :
10321                         i == Xboom_2 && j == 3 ? 10 :
10322                         i == Xboom_2 && j == 4 ? 10 :
10323                         i == Xboom_2 && j == 5 ? 12 :
10324                         i == Xboom_2 && j == 6 ? 12 :
10325                         i == Xboom_2 && j == 7 ? 12 :
10326                         special_animation && j == 4 ? 3 :
10327                         effective_action != action ? 0 :
10328                         j);
10329
10330       xxx_effective_action = effective_action;
10331       xxx_has_action_graphics = has_action_graphics;
10332     }
10333   }
10334 #endif
10335
10336   int frame = getAnimationFrame(g->anim_frames,
10337                                 g->anim_delay,
10338                                 g->anim_mode,
10339                                 g->anim_start_frame,
10340                                 sync_frame);
10341
10342
10343 #if 0
10344   return;
10345 #endif
10346
10347 #if 0
10348   if (frame_em == 7)
10349     return;
10350 #endif
10351
10352 #if 0
10353   int old_src_x = g_em->src_x;
10354   int old_src_y = g_em->src_y;
10355 #endif
10356
10357 #if 1
10358   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10359                       g->double_movement && is_backside);
10360 #else
10361   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10362                       &g_em->src_x, &g_em->src_y, FALSE);
10363 #endif
10364
10365
10366 #if 0
10367   if (tile == Ydiamond_stone)
10368     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10369            frame_em,
10370            g->anim_frames,
10371            g->anim_delay,
10372            g->anim_mode,
10373            g->anim_start_frame,
10374            sync_frame,
10375            frame,
10376            g_em->src_x, g_em->src_y,
10377            g_em->src_offset_x, g_em->src_offset_y,
10378            g_em->dst_offset_x, g_em->dst_offset_y,
10379            graphic);
10380 #endif
10381
10382
10383 #if 0
10384   return;
10385 #endif
10386
10387 #if 0
10388   if (frame_em == 7)
10389   {
10390     if (graphic == IMG_BUG_MOVING_RIGHT)
10391       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10392              g->double_movement, is_backside,
10393              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10394
10395     return;
10396   }
10397 #endif
10398
10399
10400 #if 0
10401   g_em->src_offset_x = 0;
10402   g_em->src_offset_y = 0;
10403   g_em->dst_offset_x = 0;
10404   g_em->dst_offset_y = 0;
10405   g_em->width  = TILEX;
10406   g_em->height = TILEY;
10407
10408   g_em->preserve_background = FALSE;
10409 #endif
10410
10411   /* (updating the "crumbled" graphic definitions is probably not really needed,
10412      as animations for crumbled graphics can't be longer than one EMC cycle) */
10413 #if 1
10414   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10415                            sync_frame);
10416
10417 #else
10418
10419   g_em->crumbled_bitmap = NULL;
10420   g_em->crumbled_src_x = 0;
10421   g_em->crumbled_src_y = 0;
10422
10423   g_em->has_crumbled_graphics = FALSE;
10424
10425   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10426   {
10427     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10428                                            g_crumbled->anim_delay,
10429                                            g_crumbled->anim_mode,
10430                                            g_crumbled->anim_start_frame,
10431                                            sync_frame);
10432
10433     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10434                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10435
10436     g_em->has_crumbled_graphics = TRUE;
10437   }
10438 #endif
10439
10440 #if 0
10441  {
10442    int effective_action = xxx_effective_action;
10443    int has_action_graphics = xxx_has_action_graphics;
10444
10445       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10446                                    effective_action == ACTION_MOVING  ||
10447                                    effective_action == ACTION_PUSHING ||
10448                                    effective_action == ACTION_EATING)) ||
10449           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10450                                     effective_action == ACTION_EMPTYING)))
10451       {
10452         int move_dir =
10453           (effective_action == ACTION_FALLING ||
10454            effective_action == ACTION_FILLING ||
10455            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10456         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10457         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10458         int num_steps = (i == Ydrip_s1  ? 16 :
10459                          i == Ydrip_s1B ? 16 :
10460                          i == Ydrip_s2  ? 16 :
10461                          i == Ydrip_s2B ? 16 :
10462                          i == Xsand_stonein_1 ? 32 :
10463                          i == Xsand_stonein_2 ? 32 :
10464                          i == Xsand_stonein_3 ? 32 :
10465                          i == Xsand_stonein_4 ? 32 :
10466                          i == Xsand_stoneout_1 ? 16 :
10467                          i == Xsand_stoneout_2 ? 16 : 8);
10468         int cx = ABS(dx) * (TILEX / num_steps);
10469         int cy = ABS(dy) * (TILEY / num_steps);
10470         int step_frame = (i == Ydrip_s2         ? j + 8 :
10471                           i == Ydrip_s2B        ? j + 8 :
10472                           i == Xsand_stonein_2  ? j + 8 :
10473                           i == Xsand_stonein_3  ? j + 16 :
10474                           i == Xsand_stonein_4  ? j + 24 :
10475                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10476         int step = (is_backside ? step_frame : num_steps - step_frame);
10477
10478         if (is_backside)        /* tile where movement starts */
10479         {
10480           if (dx < 0 || dy < 0)
10481           {
10482             g_em->src_offset_x = cx * step;
10483             g_em->src_offset_y = cy * step;
10484           }
10485           else
10486           {
10487             g_em->dst_offset_x = cx * step;
10488             g_em->dst_offset_y = cy * step;
10489           }
10490         }
10491         else                    /* tile where movement ends */
10492         {
10493           if (dx < 0 || dy < 0)
10494           {
10495             g_em->dst_offset_x = cx * step;
10496             g_em->dst_offset_y = cy * step;
10497           }
10498           else
10499           {
10500             g_em->src_offset_x = cx * step;
10501             g_em->src_offset_y = cy * step;
10502           }
10503         }
10504
10505         g_em->width  = TILEX - cx * step;
10506         g_em->height = TILEY - cy * step;
10507       }
10508
10509       /* create unique graphic identifier to decide if tile must be redrawn */
10510       /* bit 31 - 16 (16 bit): EM style graphic
10511          bit 15 - 12 ( 4 bit): EM style frame
10512          bit 11 -  6 ( 6 bit): graphic width
10513          bit  5 -  0 ( 6 bit): graphic height */
10514       g_em->unique_identifier =
10515         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10516  }
10517 #endif
10518
10519 }
10520
10521 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10522                                   int player_nr, int anim, int frame_em)
10523 {
10524   int element   = player_mapping[player_nr][anim].element_rnd;
10525   int action    = player_mapping[player_nr][anim].action;
10526   int direction = player_mapping[player_nr][anim].direction;
10527   int graphic = (direction == MV_NONE ?
10528                  el_act2img(element, action) :
10529                  el_act_dir2img(element, action, direction));
10530   struct GraphicInfo *g = &graphic_info[graphic];
10531   int sync_frame;
10532
10533   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10534
10535   stored_player[player_nr].StepFrame = frame_em;
10536
10537   sync_frame = stored_player[player_nr].Frame;
10538
10539   int frame = getAnimationFrame(g->anim_frames,
10540                                 g->anim_delay,
10541                                 g->anim_mode,
10542                                 g->anim_start_frame,
10543                                 sync_frame);
10544
10545   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10546                       &g_em->src_x, &g_em->src_y, FALSE);
10547
10548 #if 0
10549   printf("::: %d: %d, %d [%d]\n",
10550          player_nr,
10551          stored_player[player_nr].Frame,
10552          stored_player[player_nr].StepFrame,
10553          FrameCounter);
10554 #endif
10555 }
10556
10557 void InitGraphicInfo_EM(void)
10558 {
10559 #if 0
10560   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10561   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10562 #endif
10563   int i, j, p;
10564
10565 #if DEBUG_EM_GFX
10566   int num_em_gfx_errors = 0;
10567
10568   if (graphic_info_em_object[0][0].bitmap == NULL)
10569   {
10570     /* EM graphics not yet initialized in em_open_all() */
10571
10572     return;
10573   }
10574
10575   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10576 #endif
10577
10578   /* always start with reliable default values */
10579   for (i = 0; i < TILE_MAX; i++)
10580   {
10581     object_mapping[i].element_rnd = EL_UNKNOWN;
10582     object_mapping[i].is_backside = FALSE;
10583     object_mapping[i].action = ACTION_DEFAULT;
10584     object_mapping[i].direction = MV_NONE;
10585   }
10586
10587   /* always start with reliable default values */
10588   for (p = 0; p < MAX_PLAYERS; p++)
10589   {
10590     for (i = 0; i < SPR_MAX; i++)
10591     {
10592       player_mapping[p][i].element_rnd = EL_UNKNOWN;
10593       player_mapping[p][i].action = ACTION_DEFAULT;
10594       player_mapping[p][i].direction = MV_NONE;
10595     }
10596   }
10597
10598   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10599   {
10600     int e = em_object_mapping_list[i].element_em;
10601
10602     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10603     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10604
10605     if (em_object_mapping_list[i].action != -1)
10606       object_mapping[e].action = em_object_mapping_list[i].action;
10607
10608     if (em_object_mapping_list[i].direction != -1)
10609       object_mapping[e].direction =
10610         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10611   }
10612
10613   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10614   {
10615     int a = em_player_mapping_list[i].action_em;
10616     int p = em_player_mapping_list[i].player_nr;
10617
10618     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10619
10620     if (em_player_mapping_list[i].action != -1)
10621       player_mapping[p][a].action = em_player_mapping_list[i].action;
10622
10623     if (em_player_mapping_list[i].direction != -1)
10624       player_mapping[p][a].direction =
10625         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10626   }
10627
10628   for (i = 0; i < TILE_MAX; i++)
10629   {
10630     int element = object_mapping[i].element_rnd;
10631     int action = object_mapping[i].action;
10632     int direction = object_mapping[i].direction;
10633     boolean is_backside = object_mapping[i].is_backside;
10634 #if 0
10635     boolean action_removing = (action == ACTION_DIGGING ||
10636                                action == ACTION_SNAPPING ||
10637                                action == ACTION_COLLECTING);
10638 #endif
10639     boolean action_exploding = ((action == ACTION_EXPLODING ||
10640                                  action == ACTION_SMASHED_BY_ROCK ||
10641                                  action == ACTION_SMASHED_BY_SPRING) &&
10642                                 element != EL_DIAMOND);
10643     boolean action_active = (action == ACTION_ACTIVE);
10644     boolean action_other = (action == ACTION_OTHER);
10645
10646     for (j = 0; j < 8; j++)
10647     {
10648 #if 1
10649       int effective_element = get_effective_element_EM(i, j);
10650 #else
10651       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10652                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10653                                j < 7 ? element :
10654                                i == Xdrip_stretch ? element :
10655                                i == Xdrip_stretchB ? element :
10656                                i == Ydrip_s1 ? element :
10657                                i == Ydrip_s1B ? element :
10658                                i == Xball_1B ? element :
10659                                i == Xball_2 ? element :
10660                                i == Xball_2B ? element :
10661                                i == Yball_eat ? element :
10662                                i == Ykey_1_eat ? element :
10663                                i == Ykey_2_eat ? element :
10664                                i == Ykey_3_eat ? element :
10665                                i == Ykey_4_eat ? element :
10666                                i == Ykey_5_eat ? element :
10667                                i == Ykey_6_eat ? element :
10668                                i == Ykey_7_eat ? element :
10669                                i == Ykey_8_eat ? element :
10670                                i == Ylenses_eat ? element :
10671                                i == Ymagnify_eat ? element :
10672                                i == Ygrass_eat ? element :
10673                                i == Ydirt_eat ? element :
10674                                i == Yemerald_stone ? EL_EMERALD :
10675                                i == Ydiamond_stone ? EL_ROCK :
10676                                i == Xsand_stonein_1 ? element :
10677                                i == Xsand_stonein_2 ? element :
10678                                i == Xsand_stonein_3 ? element :
10679                                i == Xsand_stonein_4 ? element :
10680                                is_backside ? EL_EMPTY :
10681                                action_removing ? EL_EMPTY :
10682                                element);
10683 #endif
10684       int effective_action = (j < 7 ? action :
10685                               i == Xdrip_stretch ? action :
10686                               i == Xdrip_stretchB ? action :
10687                               i == Ydrip_s1 ? action :
10688                               i == Ydrip_s1B ? action :
10689                               i == Xball_1B ? action :
10690                               i == Xball_2 ? action :
10691                               i == Xball_2B ? action :
10692                               i == Yball_eat ? action :
10693                               i == Ykey_1_eat ? action :
10694                               i == Ykey_2_eat ? action :
10695                               i == Ykey_3_eat ? action :
10696                               i == Ykey_4_eat ? action :
10697                               i == Ykey_5_eat ? action :
10698                               i == Ykey_6_eat ? action :
10699                               i == Ykey_7_eat ? action :
10700                               i == Ykey_8_eat ? action :
10701                               i == Ylenses_eat ? action :
10702                               i == Ymagnify_eat ? action :
10703                               i == Ygrass_eat ? action :
10704                               i == Ydirt_eat ? action :
10705                               i == Xsand_stonein_1 ? action :
10706                               i == Xsand_stonein_2 ? action :
10707                               i == Xsand_stonein_3 ? action :
10708                               i == Xsand_stonein_4 ? action :
10709                               i == Xsand_stoneout_1 ? action :
10710                               i == Xsand_stoneout_2 ? action :
10711                               i == Xboom_android ? ACTION_EXPLODING :
10712                               action_exploding ? ACTION_EXPLODING :
10713                               action_active ? action :
10714                               action_other ? action :
10715                               ACTION_DEFAULT);
10716       int graphic = (el_act_dir2img(effective_element, effective_action,
10717                                     direction));
10718       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10719                                      direction));
10720       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10721       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10722       boolean has_action_graphics = (graphic != base_graphic);
10723       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10724       struct GraphicInfo *g = &graphic_info[graphic];
10725 #if 0
10726       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10727 #endif
10728       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10729       Bitmap *src_bitmap;
10730       int src_x, src_y;
10731       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10732       boolean special_animation = (action != ACTION_DEFAULT &&
10733                                    g->anim_frames == 3 &&
10734                                    g->anim_delay == 2 &&
10735                                    g->anim_mode & ANIM_LINEAR);
10736       int sync_frame = (i == Xdrip_stretch ? 7 :
10737                         i == Xdrip_stretchB ? 7 :
10738                         i == Ydrip_s2 ? j + 8 :
10739                         i == Ydrip_s2B ? j + 8 :
10740                         i == Xacid_1 ? 0 :
10741                         i == Xacid_2 ? 10 :
10742                         i == Xacid_3 ? 20 :
10743                         i == Xacid_4 ? 30 :
10744                         i == Xacid_5 ? 40 :
10745                         i == Xacid_6 ? 50 :
10746                         i == Xacid_7 ? 60 :
10747                         i == Xacid_8 ? 70 :
10748                         i == Xfake_acid_1 ? 0 :
10749                         i == Xfake_acid_2 ? 10 :
10750                         i == Xfake_acid_3 ? 20 :
10751                         i == Xfake_acid_4 ? 30 :
10752                         i == Xfake_acid_5 ? 40 :
10753                         i == Xfake_acid_6 ? 50 :
10754                         i == Xfake_acid_7 ? 60 :
10755                         i == Xfake_acid_8 ? 70 :
10756                         i == Xball_2 ? 7 :
10757                         i == Xball_2B ? j + 8 :
10758                         i == Yball_eat ? j + 1 :
10759                         i == Ykey_1_eat ? j + 1 :
10760                         i == Ykey_2_eat ? j + 1 :
10761                         i == Ykey_3_eat ? j + 1 :
10762                         i == Ykey_4_eat ? j + 1 :
10763                         i == Ykey_5_eat ? j + 1 :
10764                         i == Ykey_6_eat ? j + 1 :
10765                         i == Ykey_7_eat ? j + 1 :
10766                         i == Ykey_8_eat ? j + 1 :
10767                         i == Ylenses_eat ? j + 1 :
10768                         i == Ymagnify_eat ? j + 1 :
10769                         i == Ygrass_eat ? j + 1 :
10770                         i == Ydirt_eat ? j + 1 :
10771                         i == Xamoeba_1 ? 0 :
10772                         i == Xamoeba_2 ? 1 :
10773                         i == Xamoeba_3 ? 2 :
10774                         i == Xamoeba_4 ? 3 :
10775                         i == Xamoeba_5 ? 0 :
10776                         i == Xamoeba_6 ? 1 :
10777                         i == Xamoeba_7 ? 2 :
10778                         i == Xamoeba_8 ? 3 :
10779                         i == Xexit_2 ? j + 8 :
10780                         i == Xexit_3 ? j + 16 :
10781                         i == Xdynamite_1 ? 0 :
10782                         i == Xdynamite_2 ? 8 :
10783                         i == Xdynamite_3 ? 16 :
10784                         i == Xdynamite_4 ? 24 :
10785                         i == Xsand_stonein_1 ? j + 1 :
10786                         i == Xsand_stonein_2 ? j + 9 :
10787                         i == Xsand_stonein_3 ? j + 17 :
10788                         i == Xsand_stonein_4 ? j + 25 :
10789                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10790                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10791                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10792                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10793                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10794                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10795                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10796                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10797                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10798                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10799                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10800                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10801                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10802                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10803                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10804                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10805                         i == Xboom_bug && j == 1 ? 2 :
10806                         i == Xboom_bug && j == 2 ? 2 :
10807                         i == Xboom_bug && j == 3 ? 4 :
10808                         i == Xboom_bug && j == 4 ? 4 :
10809                         i == Xboom_bug && j == 5 ? 2 :
10810                         i == Xboom_bug && j == 6 ? 2 :
10811                         i == Xboom_bug && j == 7 ? 0 :
10812                         i == Xboom_bomb && j == 1 ? 2 :
10813                         i == Xboom_bomb && j == 2 ? 2 :
10814                         i == Xboom_bomb && j == 3 ? 4 :
10815                         i == Xboom_bomb && j == 4 ? 4 :
10816                         i == Xboom_bomb && j == 5 ? 2 :
10817                         i == Xboom_bomb && j == 6 ? 2 :
10818                         i == Xboom_bomb && j == 7 ? 0 :
10819                         i == Xboom_android && j == 7 ? 6 :
10820                         i == Xboom_1 && j == 1 ? 2 :
10821                         i == Xboom_1 && j == 2 ? 2 :
10822                         i == Xboom_1 && j == 3 ? 4 :
10823                         i == Xboom_1 && j == 4 ? 4 :
10824                         i == Xboom_1 && j == 5 ? 6 :
10825                         i == Xboom_1 && j == 6 ? 6 :
10826                         i == Xboom_1 && j == 7 ? 8 :
10827                         i == Xboom_2 && j == 0 ? 8 :
10828                         i == Xboom_2 && j == 1 ? 8 :
10829                         i == Xboom_2 && j == 2 ? 10 :
10830                         i == Xboom_2 && j == 3 ? 10 :
10831                         i == Xboom_2 && j == 4 ? 10 :
10832                         i == Xboom_2 && j == 5 ? 12 :
10833                         i == Xboom_2 && j == 6 ? 12 :
10834                         i == Xboom_2 && j == 7 ? 12 :
10835                         special_animation && j == 4 ? 3 :
10836                         effective_action != action ? 0 :
10837                         j);
10838
10839 #if DEBUG_EM_GFX
10840       Bitmap *debug_bitmap = g_em->bitmap;
10841       int debug_src_x = g_em->src_x;
10842       int debug_src_y = g_em->src_y;
10843 #endif
10844
10845       int frame = getAnimationFrame(g->anim_frames,
10846                                     g->anim_delay,
10847                                     g->anim_mode,
10848                                     g->anim_start_frame,
10849                                     sync_frame);
10850
10851       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10852                           g->double_movement && is_backside);
10853
10854       g_em->bitmap = src_bitmap;
10855       g_em->src_x = src_x;
10856       g_em->src_y = src_y;
10857       g_em->src_offset_x = 0;
10858       g_em->src_offset_y = 0;
10859       g_em->dst_offset_x = 0;
10860       g_em->dst_offset_y = 0;
10861       g_em->width  = TILEX;
10862       g_em->height = TILEY;
10863
10864       g_em->preserve_background = FALSE;
10865
10866 #if 1
10867       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10868                                sync_frame);
10869
10870 #else
10871
10872       g_em->crumbled_bitmap = NULL;
10873       g_em->crumbled_src_x = 0;
10874       g_em->crumbled_src_y = 0;
10875       g_em->crumbled_border_size = 0;
10876
10877       g_em->has_crumbled_graphics = FALSE;
10878
10879 #if 0
10880       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10881         printf("::: empty crumbled: %d [%s], %d, %d\n",
10882                effective_element, element_info[effective_element].token_name,
10883                effective_action, direction);
10884 #endif
10885
10886       /* if element can be crumbled, but certain action graphics are just empty
10887          space (like instantly snapping sand to empty space in 1 frame), do not
10888          treat these empty space graphics as crumbled graphics in EMC engine */
10889       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10890       {
10891         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10892                                                g_crumbled->anim_delay,
10893                                                g_crumbled->anim_mode,
10894                                                g_crumbled->anim_start_frame,
10895                                                sync_frame);
10896
10897         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10898
10899         g_em->has_crumbled_graphics = TRUE;
10900         g_em->crumbled_bitmap = src_bitmap;
10901         g_em->crumbled_src_x = src_x;
10902         g_em->crumbled_src_y = src_y;
10903         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10904
10905
10906 #if 0
10907         if (g_em == &graphic_info_em_object[207][0])
10908           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10909                  graphic_info_em_object[207][0].crumbled_src_x,
10910                  graphic_info_em_object[207][0].crumbled_src_y,
10911
10912                  crumbled, frame, src_x, src_y,
10913
10914                  g->anim_frames,
10915                  g->anim_delay,
10916                  g->anim_mode,
10917                  g->anim_start_frame,
10918                  sync_frame,
10919                  gfx.anim_random_frame,
10920                  frame);
10921 #endif
10922
10923 #if 0
10924         printf("::: EMC tile %d is crumbled\n", i);
10925 #endif
10926       }
10927 #endif
10928
10929 #if 0
10930       if (element == EL_ROCK &&
10931           effective_action == ACTION_FILLING)
10932         printf("::: has_action_graphics == %d\n", has_action_graphics);
10933 #endif
10934
10935       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10936                                    effective_action == ACTION_MOVING  ||
10937                                    effective_action == ACTION_PUSHING ||
10938                                    effective_action == ACTION_EATING)) ||
10939           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10940                                     effective_action == ACTION_EMPTYING)))
10941       {
10942         int move_dir =
10943           (effective_action == ACTION_FALLING ||
10944            effective_action == ACTION_FILLING ||
10945            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10946         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10947         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10948         int num_steps = (i == Ydrip_s1  ? 16 :
10949                          i == Ydrip_s1B ? 16 :
10950                          i == Ydrip_s2  ? 16 :
10951                          i == Ydrip_s2B ? 16 :
10952                          i == Xsand_stonein_1 ? 32 :
10953                          i == Xsand_stonein_2 ? 32 :
10954                          i == Xsand_stonein_3 ? 32 :
10955                          i == Xsand_stonein_4 ? 32 :
10956                          i == Xsand_stoneout_1 ? 16 :
10957                          i == Xsand_stoneout_2 ? 16 : 8);
10958         int cx = ABS(dx) * (TILEX / num_steps);
10959         int cy = ABS(dy) * (TILEY / num_steps);
10960         int step_frame = (i == Ydrip_s2         ? j + 8 :
10961                           i == Ydrip_s2B        ? j + 8 :
10962                           i == Xsand_stonein_2  ? j + 8 :
10963                           i == Xsand_stonein_3  ? j + 16 :
10964                           i == Xsand_stonein_4  ? j + 24 :
10965                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10966         int step = (is_backside ? step_frame : num_steps - step_frame);
10967
10968         if (is_backside)        /* tile where movement starts */
10969         {
10970           if (dx < 0 || dy < 0)
10971           {
10972             g_em->src_offset_x = cx * step;
10973             g_em->src_offset_y = cy * step;
10974           }
10975           else
10976           {
10977             g_em->dst_offset_x = cx * step;
10978             g_em->dst_offset_y = cy * step;
10979           }
10980         }
10981         else                    /* tile where movement ends */
10982         {
10983           if (dx < 0 || dy < 0)
10984           {
10985             g_em->dst_offset_x = cx * step;
10986             g_em->dst_offset_y = cy * step;
10987           }
10988           else
10989           {
10990             g_em->src_offset_x = cx * step;
10991             g_em->src_offset_y = cy * step;
10992           }
10993         }
10994
10995         g_em->width  = TILEX - cx * step;
10996         g_em->height = TILEY - cy * step;
10997       }
10998
10999       /* create unique graphic identifier to decide if tile must be redrawn */
11000       /* bit 31 - 16 (16 bit): EM style graphic
11001          bit 15 - 12 ( 4 bit): EM style frame
11002          bit 11 -  6 ( 6 bit): graphic width
11003          bit  5 -  0 ( 6 bit): graphic height */
11004       g_em->unique_identifier =
11005         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11006
11007 #if DEBUG_EM_GFX
11008
11009       /* skip check for EMC elements not contained in original EMC artwork */
11010       if (element == EL_EMC_FAKE_ACID)
11011         continue;
11012
11013       if (g_em->bitmap != debug_bitmap ||
11014           g_em->src_x != debug_src_x ||
11015           g_em->src_y != debug_src_y ||
11016           g_em->src_offset_x != 0 ||
11017           g_em->src_offset_y != 0 ||
11018           g_em->dst_offset_x != 0 ||
11019           g_em->dst_offset_y != 0 ||
11020           g_em->width != TILEX ||
11021           g_em->height != TILEY)
11022       {
11023         static int last_i = -1;
11024
11025         if (i != last_i)
11026         {
11027           printf("\n");
11028           last_i = i;
11029         }
11030
11031         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11032                i, element, element_info[element].token_name,
11033                element_action_info[effective_action].suffix, direction);
11034
11035         if (element != effective_element)
11036           printf(" [%d ('%s')]",
11037                  effective_element,
11038                  element_info[effective_element].token_name);
11039
11040         printf("\n");
11041
11042         if (g_em->bitmap != debug_bitmap)
11043           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11044                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11045
11046         if (g_em->src_x != debug_src_x ||
11047             g_em->src_y != debug_src_y)
11048           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11049                  j, (is_backside ? 'B' : 'F'),
11050                  g_em->src_x, g_em->src_y,
11051                  g_em->src_x / 32, g_em->src_y / 32,
11052                  debug_src_x, debug_src_y,
11053                  debug_src_x / 32, debug_src_y / 32);
11054
11055         if (g_em->src_offset_x != 0 ||
11056             g_em->src_offset_y != 0 ||
11057             g_em->dst_offset_x != 0 ||
11058             g_em->dst_offset_y != 0)
11059           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11060                  j, is_backside,
11061                  g_em->src_offset_x, g_em->src_offset_y,
11062                  g_em->dst_offset_x, g_em->dst_offset_y);
11063
11064         if (g_em->width != TILEX ||
11065             g_em->height != TILEY)
11066           printf("    %d (%d): size %d,%d should be %d,%d\n",
11067                  j, is_backside,
11068                  g_em->width, g_em->height, TILEX, TILEY);
11069
11070         num_em_gfx_errors++;
11071       }
11072 #endif
11073
11074     }
11075   }
11076
11077   for (i = 0; i < TILE_MAX; i++)
11078   {
11079     for (j = 0; j < 8; j++)
11080     {
11081       int element = object_mapping[i].element_rnd;
11082       int action = object_mapping[i].action;
11083       int direction = object_mapping[i].direction;
11084       boolean is_backside = object_mapping[i].is_backside;
11085       int graphic_action  = el_act_dir2img(element, action, direction);
11086       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11087
11088       if ((action == ACTION_SMASHED_BY_ROCK ||
11089            action == ACTION_SMASHED_BY_SPRING ||
11090            action == ACTION_EATING) &&
11091           graphic_action == graphic_default)
11092       {
11093         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
11094                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11095                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
11096                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11097                  Xspring);
11098
11099         /* no separate animation for "smashed by rock" -- use rock instead */
11100         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11101         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11102
11103         g_em->bitmap            = g_xx->bitmap;
11104         g_em->src_x             = g_xx->src_x;
11105         g_em->src_y             = g_xx->src_y;
11106         g_em->src_offset_x      = g_xx->src_offset_x;
11107         g_em->src_offset_y      = g_xx->src_offset_y;
11108         g_em->dst_offset_x      = g_xx->dst_offset_x;
11109         g_em->dst_offset_y      = g_xx->dst_offset_y;
11110         g_em->width             = g_xx->width;
11111         g_em->height            = g_xx->height;
11112         g_em->unique_identifier = g_xx->unique_identifier;
11113
11114         if (!is_backside)
11115           g_em->preserve_background = TRUE;
11116       }
11117     }
11118   }
11119
11120   for (p = 0; p < MAX_PLAYERS; p++)
11121   {
11122     for (i = 0; i < SPR_MAX; i++)
11123     {
11124       int element = player_mapping[p][i].element_rnd;
11125       int action = player_mapping[p][i].action;
11126       int direction = player_mapping[p][i].direction;
11127
11128       for (j = 0; j < 8; j++)
11129       {
11130         int effective_element = element;
11131         int effective_action = action;
11132         int graphic = (direction == MV_NONE ?
11133                        el_act2img(effective_element, effective_action) :
11134                        el_act_dir2img(effective_element, effective_action,
11135                                       direction));
11136         struct GraphicInfo *g = &graphic_info[graphic];
11137         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11138         Bitmap *src_bitmap;
11139         int src_x, src_y;
11140         int sync_frame = j;
11141
11142 #if DEBUG_EM_GFX
11143         Bitmap *debug_bitmap = g_em->bitmap;
11144         int debug_src_x = g_em->src_x;
11145         int debug_src_y = g_em->src_y;
11146 #endif
11147
11148         int frame = getAnimationFrame(g->anim_frames,
11149                                       g->anim_delay,
11150                                       g->anim_mode,
11151                                       g->anim_start_frame,
11152                                       sync_frame);
11153
11154         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11155
11156         g_em->bitmap = src_bitmap;
11157         g_em->src_x = src_x;
11158         g_em->src_y = src_y;
11159         g_em->src_offset_x = 0;
11160         g_em->src_offset_y = 0;
11161         g_em->dst_offset_x = 0;
11162         g_em->dst_offset_y = 0;
11163         g_em->width  = TILEX;
11164         g_em->height = TILEY;
11165
11166 #if DEBUG_EM_GFX
11167
11168         /* skip check for EMC elements not contained in original EMC artwork */
11169         if (element == EL_PLAYER_3 ||
11170             element == EL_PLAYER_4)
11171           continue;
11172
11173         if (g_em->bitmap != debug_bitmap ||
11174             g_em->src_x != debug_src_x ||
11175             g_em->src_y != debug_src_y)
11176         {
11177           static int last_i = -1;
11178
11179           if (i != last_i)
11180           {
11181             printf("\n");
11182             last_i = i;
11183           }
11184
11185           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11186                  p, i, element, element_info[element].token_name,
11187                  element_action_info[effective_action].suffix, direction);
11188
11189           if (element != effective_element)
11190             printf(" [%d ('%s')]",
11191                    effective_element,
11192                    element_info[effective_element].token_name);
11193
11194           printf("\n");
11195
11196           if (g_em->bitmap != debug_bitmap)
11197             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
11198                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
11199
11200           if (g_em->src_x != debug_src_x ||
11201               g_em->src_y != debug_src_y)
11202             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11203                    j,
11204                    g_em->src_x, g_em->src_y,
11205                    g_em->src_x / 32, g_em->src_y / 32,
11206                    debug_src_x, debug_src_y,
11207                    debug_src_x / 32, debug_src_y / 32);
11208
11209           num_em_gfx_errors++;
11210         }
11211 #endif
11212
11213       }
11214     }
11215   }
11216
11217 #if DEBUG_EM_GFX
11218   printf("\n");
11219   printf("::: [%d errors found]\n", num_em_gfx_errors);
11220
11221   exit(0);
11222 #endif
11223 }
11224
11225 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11226                             boolean any_player_moving,
11227                             boolean player_is_dropping)
11228 {
11229   if (tape.single_step && tape.recording && !tape.pausing)
11230   {
11231 #if 0
11232     boolean active_players = FALSE;
11233     int i;
11234
11235     for (i = 0; i < MAX_PLAYERS; i++)
11236       if (action[i] != JOY_NO_ACTION)
11237         active_players = TRUE;
11238 #endif
11239
11240     // if (frame == 0)
11241     if (frame == 0 && !player_is_dropping)
11242       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11243   }
11244 }
11245
11246 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11247                             boolean murphy_is_dropping)
11248 {
11249 #if 0
11250   printf("::: waiting: %d, dropping: %d\n",
11251          murphy_is_waiting, murphy_is_dropping);
11252 #endif
11253
11254   if (tape.single_step && tape.recording && !tape.pausing)
11255   {
11256     // if (murphy_is_waiting || murphy_is_dropping)
11257     if (murphy_is_waiting)
11258     {
11259 #if 0
11260       printf("::: murphy is waiting -> pause mode\n");
11261 #endif
11262
11263       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11264     }
11265   }
11266 }
11267
11268 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11269                          int graphic, int sync_frame, int x, int y)
11270 {
11271   int frame = getGraphicAnimationFrame(graphic, sync_frame);
11272
11273   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11274 }
11275
11276 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11277 {
11278   return (IS_NEXT_FRAME(sync_frame, graphic));
11279 }
11280
11281 int getGraphicInfo_Delay(int graphic)
11282 {
11283   return graphic_info[graphic].anim_delay;
11284 }
11285
11286 void PlayMenuSoundExt(int sound)
11287 {
11288   if (sound == SND_UNDEFINED)
11289     return;
11290
11291   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11292       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11293     return;
11294
11295   if (IS_LOOP_SOUND(sound))
11296     PlaySoundLoop(sound);
11297   else
11298     PlaySound(sound);
11299 }
11300
11301 void PlayMenuSound()
11302 {
11303   PlayMenuSoundExt(menu.sound[game_status]);
11304 }
11305
11306 void PlayMenuSoundStereo(int sound, int stereo_position)
11307 {
11308   if (sound == SND_UNDEFINED)
11309     return;
11310
11311   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11312       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11313     return;
11314
11315   if (IS_LOOP_SOUND(sound))
11316     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11317   else
11318     PlaySoundStereo(sound, stereo_position);
11319 }
11320
11321 void PlayMenuSoundIfLoopExt(int sound)
11322 {
11323   if (sound == SND_UNDEFINED)
11324     return;
11325
11326   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11327       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11328     return;
11329
11330   if (IS_LOOP_SOUND(sound))
11331     PlaySoundLoop(sound);
11332 }
11333
11334 void PlayMenuSoundIfLoop()
11335 {
11336   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11337 }
11338
11339 void PlayMenuMusicExt(int music)
11340 {
11341   if (music == MUS_UNDEFINED)
11342     return;
11343
11344   if (!setup.sound_music)
11345     return;
11346
11347   PlayMusic(music);
11348 }
11349
11350 void PlayMenuMusic()
11351 {
11352   PlayMenuMusicExt(menu.music[game_status]);
11353 }
11354
11355 void PlaySoundActivating()
11356 {
11357 #if 0
11358   PlaySound(SND_MENU_ITEM_ACTIVATING);
11359 #endif
11360 }
11361
11362 void PlaySoundSelecting()
11363 {
11364 #if 0
11365   PlaySound(SND_MENU_ITEM_SELECTING);
11366 #endif
11367 }
11368
11369 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11370 {
11371   boolean change_fullscreen = (setup.fullscreen !=
11372                                video.fullscreen_enabled);
11373   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11374                                     !strEqual(setup.fullscreen_mode,
11375                                               video.fullscreen_mode_current));
11376   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11377                                            setup.window_scaling_percent !=
11378                                            video.window_scaling_percent);
11379
11380   if (change_window_scaling_percent && video.fullscreen_enabled)
11381     return;
11382
11383   if (!change_window_scaling_percent && !video.fullscreen_available)
11384     return;
11385
11386 #if defined(TARGET_SDL2)
11387   if (change_window_scaling_percent)
11388   {
11389     SDLSetWindowScaling(setup.window_scaling_percent);
11390
11391     return;
11392   }
11393   else if (change_fullscreen)
11394   {
11395     SDLSetWindowFullscreen(setup.fullscreen);
11396
11397     /* set setup value according to successfully changed fullscreen mode */
11398     setup.fullscreen = video.fullscreen_enabled;
11399
11400     return;
11401   }
11402 #endif
11403
11404   if (change_fullscreen ||
11405       change_fullscreen_mode ||
11406       change_window_scaling_percent)
11407   {
11408     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11409
11410     /* save backbuffer content which gets lost when toggling fullscreen mode */
11411     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11412
11413     if (change_fullscreen_mode)
11414     {
11415       /* keep fullscreen, but change fullscreen mode (screen resolution) */
11416       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
11417     }
11418
11419     if (change_window_scaling_percent)
11420     {
11421       /* keep window mode, but change window scaling */
11422       video.fullscreen_enabled = TRUE;          /* force new window scaling */
11423     }
11424
11425     /* toggle fullscreen */
11426     ChangeVideoModeIfNeeded(setup.fullscreen);
11427
11428     /* set setup value according to successfully changed fullscreen mode */
11429     setup.fullscreen = video.fullscreen_enabled;
11430
11431     /* restore backbuffer content from temporary backbuffer backup bitmap */
11432     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11433
11434     FreeBitmap(tmp_backbuffer);
11435
11436 #if 1
11437     /* update visible window/screen */
11438     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11439 #else
11440     redraw_mask = REDRAW_ALL;
11441 #endif
11442   }
11443 }
11444
11445 void ChangeViewportPropertiesIfNeeded()
11446 {
11447 #if 0
11448   int *door_1_x = &DX;
11449   int *door_1_y = &DY;
11450   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11451   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11452 #endif
11453 #if 1
11454   int gfx_game_mode = game_status;
11455 #else
11456   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11457                        game_status == GAME_MODE_EDITOR ? game_status :
11458                        GAME_MODE_MAIN);
11459 #endif
11460   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11461                         game_status);
11462   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11463   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11464   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11465   struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11466   int border_size       = vp_playfield->border_size;
11467   int new_sx            = vp_playfield->x + border_size;
11468   int new_sy            = vp_playfield->y + border_size;
11469   int new_sxsize        = vp_playfield->width  - 2 * border_size;
11470   int new_sysize        = vp_playfield->height - 2 * border_size;
11471   int new_real_sx       = vp_playfield->x;
11472   int new_real_sy       = vp_playfield->y;
11473   int new_full_sxsize   = vp_playfield->width;
11474   int new_full_sysize   = vp_playfield->height;
11475   int new_dx            = vp_door_1->x;
11476   int new_dy            = vp_door_1->y;
11477   int new_dxsize        = vp_door_1->width;
11478   int new_dysize        = vp_door_1->height;
11479   int new_vx            = vp_door_2->x;
11480   int new_vy            = vp_door_2->y;
11481   int new_vxsize        = vp_door_2->width;
11482   int new_vysize        = vp_door_2->height;
11483   int new_ex            = vp_door_3->x;
11484   int new_ey            = vp_door_3->y;
11485   int new_exsize        = vp_door_3->width;
11486   int new_eysize        = vp_door_3->height;
11487 #if NEW_TILESIZE
11488   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11489   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11490                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11491   int new_scr_fieldx = new_sxsize / tilesize;
11492   int new_scr_fieldy = new_sysize / tilesize;
11493   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11494   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11495 #else
11496   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
11497   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11498 #endif
11499   boolean init_gfx_buffers = FALSE;
11500   boolean init_video_buffer = FALSE;
11501   boolean init_gadgets_and_toons = FALSE;
11502   boolean init_em_graphics = FALSE;
11503
11504 #if 0
11505   /* !!! TEST ONLY !!! */
11506   // InitGfxBuffers();
11507   return;
11508 #endif
11509
11510   if (viewport.window.width  != WIN_XSIZE ||
11511       viewport.window.height != WIN_YSIZE)
11512   {
11513     WIN_XSIZE = viewport.window.width;
11514     WIN_YSIZE = viewport.window.height;
11515
11516 #if 1
11517     init_video_buffer = TRUE;
11518     init_gfx_buffers = TRUE;
11519 #else
11520     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11521     InitGfxBuffers();
11522
11523 #if 1
11524     SetDrawDeactivationMask(REDRAW_NONE);
11525     SetDrawBackgroundMask(REDRAW_FIELD);
11526
11527     // RedrawBackground();
11528 #endif
11529 #endif
11530
11531     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11532   }
11533
11534   if (new_scr_fieldx != SCR_FIELDX ||
11535       new_scr_fieldy != SCR_FIELDY)
11536   {
11537     /* this always toggles between MAIN and GAME when using small tile size */
11538
11539     SCR_FIELDX = new_scr_fieldx;
11540     SCR_FIELDY = new_scr_fieldy;
11541
11542     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11543   }
11544
11545 #if 0
11546   if (new_tilesize_var != TILESIZE_VAR &&
11547       gfx_game_mode == GAME_MODE_PLAYING)
11548   {
11549     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11550
11551     TILESIZE_VAR = new_tilesize_var;
11552
11553     init_gfx_buffers = TRUE;
11554
11555     // printf("::: tilesize: init_gfx_buffers\n");
11556   }
11557 #endif
11558
11559   if (new_sx != SX ||
11560       new_sy != SY ||
11561       new_dx != DX ||
11562       new_dy != DY ||
11563       new_vx != VX ||
11564       new_vy != VY ||
11565       new_ex != EX ||
11566       new_ey != EY ||
11567       new_sxsize != SXSIZE ||
11568       new_sysize != SYSIZE ||
11569       new_dxsize != DXSIZE ||
11570       new_dysize != DYSIZE ||
11571       new_vxsize != VXSIZE ||
11572       new_vysize != VYSIZE ||
11573       new_exsize != EXSIZE ||
11574       new_eysize != EYSIZE ||
11575       new_real_sx != REAL_SX ||
11576       new_real_sy != REAL_SY ||
11577       new_full_sxsize != FULL_SXSIZE ||
11578       new_full_sysize != FULL_SYSIZE ||
11579       new_tilesize_var != TILESIZE_VAR
11580 #if 0
11581       ||
11582       vp_door_1->x != *door_1_x ||
11583       vp_door_1->y != *door_1_y ||
11584       vp_door_2->x != *door_2_x ||
11585       vp_door_2->y != *door_2_y
11586 #endif
11587       )
11588   {
11589 #if 1
11590     if (new_tilesize_var != TILESIZE_VAR)
11591     {
11592       // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11593
11594       // changing tile size invalidates scroll values of engine snapshots
11595       FreeEngineSnapshot();
11596
11597       // changing tile size requires update of graphic mapping for EM engine
11598       init_em_graphics = TRUE;
11599     }
11600 #endif
11601
11602     SX = new_sx;
11603     SY = new_sy;
11604     DX = new_dx;
11605     DY = new_dy;
11606     VX = new_vx;
11607     VY = new_vy;
11608     EX = new_ex;
11609     EY = new_ey;
11610     SXSIZE = new_sxsize;
11611     SYSIZE = new_sysize;
11612     DXSIZE = new_dxsize;
11613     DYSIZE = new_dysize;
11614     VXSIZE = new_vxsize;
11615     VYSIZE = new_vysize;
11616     EXSIZE = new_exsize;
11617     EYSIZE = new_eysize;
11618     REAL_SX = new_real_sx;
11619     REAL_SY = new_real_sy;
11620     FULL_SXSIZE = new_full_sxsize;
11621     FULL_SYSIZE = new_full_sysize;
11622     TILESIZE_VAR = new_tilesize_var;
11623
11624 #if 0
11625     printf("::: %d, %d, %d [%d]\n",
11626            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11627            setup.small_game_graphics);
11628 #endif
11629
11630 #if 0
11631     *door_1_x = vp_door_1->x;
11632     *door_1_y = vp_door_1->y;
11633     *door_2_x = vp_door_2->x;
11634     *door_2_y = vp_door_2->y;
11635 #endif
11636
11637 #if 1
11638     init_gfx_buffers = TRUE;
11639
11640     // printf("::: viewports: init_gfx_buffers\n");
11641 #else
11642     InitGfxBuffers();
11643 #endif
11644
11645 #if 0
11646     if (gfx_game_mode == GAME_MODE_MAIN)
11647 #endif
11648     {
11649 #if 1
11650       init_gadgets_and_toons = TRUE;
11651
11652       // printf("::: viewports: init_gadgets_and_toons\n");
11653 #else
11654       InitGadgets();
11655       InitToons();
11656 #endif
11657     }
11658   }
11659
11660   if (init_gfx_buffers)
11661   {
11662     // printf("::: init_gfx_buffers\n");
11663
11664     SCR_FIELDX = new_scr_fieldx_buffers;
11665     SCR_FIELDY = new_scr_fieldy_buffers;
11666
11667     InitGfxBuffers();
11668
11669     SCR_FIELDX = new_scr_fieldx;
11670     SCR_FIELDY = new_scr_fieldy;
11671   }
11672
11673   if (init_video_buffer)
11674   {
11675     // printf("::: init_video_buffer\n");
11676
11677     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11678
11679     SetDrawDeactivationMask(REDRAW_NONE);
11680     SetDrawBackgroundMask(REDRAW_FIELD);
11681   }
11682
11683   if (init_gadgets_and_toons)
11684   {
11685     // printf("::: init_gadgets_and_toons\n");
11686
11687     InitGadgets();
11688     InitToons();
11689   }
11690
11691   if (init_em_graphics)
11692   {
11693       InitGraphicInfo_EM();
11694   }
11695
11696 #if 0
11697   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
11698 #endif
11699 }