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