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