treat Android 'menu' button as 'ok' button in requester dialogs
[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 #if defined(TARGET_SDL2)
4604             case KSYM_Menu:
4605 #endif
4606               result = 1;
4607               break;
4608
4609             case KSYM_Escape:
4610 #if defined(TARGET_SDL2)
4611             case KSYM_Back:
4612 #endif
4613               result = 0;
4614               break;
4615
4616             default:
4617               break;
4618           }
4619
4620           if (req_state & REQ_PLAYER)
4621             result = 0;
4622           break;
4623
4624         case EVENT_KEYRELEASE:
4625           ClearPlayerAction();
4626           break;
4627
4628         default:
4629           HandleOtherEvents(&event);
4630           break;
4631       }
4632     }
4633     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4634     {
4635       int joy = AnyJoystick();
4636
4637       if (joy & JOY_BUTTON_1)
4638         result = 1;
4639       else if (joy & JOY_BUTTON_2)
4640         result = 0;
4641     }
4642
4643 #if 1
4644
4645     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4646     {
4647       HandleGameActions();
4648     }
4649     else
4650     {
4651       DoAnimation();
4652
4653       if (!PendingEvent())      /* delay only if no pending events */
4654         Delay(10);
4655     }
4656
4657 #if 1
4658     game_status = GAME_MODE_PSEUDO_DOOR;
4659 #endif
4660
4661     BackToFront();
4662
4663 #if 1
4664     game_status = last_game_status;     /* restore current game status */
4665 #endif
4666
4667 #else
4668
4669     DoAnimation();
4670
4671 #if 1
4672     if (!PendingEvent())        /* delay only if no pending events */
4673       Delay(10);
4674 #else
4675     /* don't eat all CPU time */
4676     Delay(10);
4677 #endif
4678
4679 #endif
4680   }
4681
4682   return result;
4683 }
4684
4685 static boolean RequestDoor(char *text, unsigned int req_state)
4686 {
4687   unsigned int old_door_state;
4688   int last_game_status = game_status;   /* save current game status */
4689   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4690   int font_nr = FONT_TEXT_2;
4691   char *text_ptr;
4692   int result;
4693   int ty;
4694
4695   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4696   {
4697     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4698     font_nr = FONT_TEXT_1;
4699   }
4700
4701   if (game_status == GAME_MODE_PLAYING)
4702   {
4703 #if 1
4704     BlitScreenToBitmap(backbuffer);
4705 #else
4706     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4707       BlitScreenToBitmap_EM(backbuffer);
4708     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4709       BlitScreenToBitmap_SP(backbuffer);
4710 #endif
4711   }
4712
4713   /* disable deactivated drawing when quick-loading level tape recording */
4714   if (tape.playing && tape.deactivate_display)
4715     TapeDeactivateDisplayOff(TRUE);
4716
4717   SetMouseCursor(CURSOR_DEFAULT);
4718
4719 #if defined(NETWORK_AVALIABLE)
4720   /* pause network game while waiting for request to answer */
4721   if (options.network &&
4722       game_status == GAME_MODE_PLAYING &&
4723       req_state & REQUEST_WAIT_FOR_INPUT)
4724     SendToServer_PausePlaying();
4725 #endif
4726
4727   old_door_state = GetDoorState();
4728
4729   /* simulate releasing mouse button over last gadget, if still pressed */
4730   if (button_status)
4731     HandleGadgets(-1, -1, 0);
4732
4733   UnmapAllGadgets();
4734
4735   /* draw released gadget before proceeding */
4736   // BackToFront();
4737
4738   if (old_door_state & DOOR_OPEN_1)
4739   {
4740     CloseDoor(DOOR_CLOSE_1);
4741
4742     /* save old door content */
4743 #if 1
4744     BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4745                0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4746 #else
4747     BlitBitmap(bitmap_db_door, bitmap_db_door,
4748                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4749                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4750 #endif
4751   }
4752
4753   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4754   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4755
4756   /* clear door drawing field */
4757   DrawBackground(DX, DY, DXSIZE, DYSIZE);
4758
4759   /* force DOOR font inside door area */
4760   game_status = GAME_MODE_PSEUDO_DOOR;
4761
4762   /* write text for request */
4763   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4764   {
4765     char text_line[max_request_line_len + 1];
4766     int tx, tl, tc = 0;
4767
4768     if (!*text_ptr)
4769       break;
4770
4771     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4772     {
4773       tc = *(text_ptr + tx);
4774       // if (!tc || tc == ' ')
4775       if (!tc || tc == ' ' || tc == '?' || tc == '!')
4776         break;
4777     }
4778
4779     if ((tc == '?' || tc == '!') && tl == 0)
4780       tl = 1;
4781
4782     if (!tl)
4783     { 
4784       text_ptr++; 
4785       ty--; 
4786       continue; 
4787     }
4788
4789     strncpy(text_line, text_ptr, tl);
4790     text_line[tl] = 0;
4791
4792     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4793              DY + 8 + ty * (getFontHeight(font_nr) + 2),
4794              text_line, font_nr);
4795
4796     text_ptr += tl + (tc == ' ' ? 1 : 0);
4797     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4798   }
4799
4800   game_status = last_game_status;       /* restore current game status */
4801
4802   if (req_state & REQ_ASK)
4803   {
4804     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4805     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4806   }
4807   else if (req_state & REQ_CONFIRM)
4808   {
4809     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4810   }
4811   else if (req_state & REQ_PLAYER)
4812   {
4813     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4814     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4815     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4816     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4817   }
4818
4819   /* copy request gadgets to door backbuffer */
4820 #if 1
4821   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4822 #else
4823   BlitBitmap(drawto, bitmap_db_door,
4824              DX, DY, DXSIZE, DYSIZE,
4825              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4826 #endif
4827
4828   OpenDoor(DOOR_OPEN_1);
4829
4830   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4831   {
4832     if (game_status == GAME_MODE_PLAYING)
4833     {
4834       SetPanelBackground();
4835       SetDrawBackgroundMask(REDRAW_DOOR_1);
4836     }
4837     else
4838     {
4839       SetDrawBackgroundMask(REDRAW_FIELD);
4840     }
4841
4842     return FALSE;
4843   }
4844
4845   if (game_status != GAME_MODE_MAIN)
4846     InitAnimation();
4847
4848   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4849
4850   // ---------- handle request buttons ----------
4851   result = RequestHandleEvents(req_state);
4852
4853   if (game_status != GAME_MODE_MAIN)
4854     StopAnimation();
4855
4856   UnmapToolButtons();
4857
4858   if (!(req_state & REQ_STAY_OPEN))
4859   {
4860     CloseDoor(DOOR_CLOSE_1);
4861
4862     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4863         (req_state & REQ_REOPEN))
4864       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4865   }
4866
4867   RemapAllGadgets();
4868
4869   if (game_status == GAME_MODE_PLAYING)
4870   {
4871     SetPanelBackground();
4872     SetDrawBackgroundMask(REDRAW_DOOR_1);
4873   }
4874   else
4875   {
4876     SetDrawBackgroundMask(REDRAW_FIELD);
4877   }
4878
4879 #if defined(NETWORK_AVALIABLE)
4880   /* continue network game after request */
4881   if (options.network &&
4882       game_status == GAME_MODE_PLAYING &&
4883       req_state & REQUEST_WAIT_FOR_INPUT)
4884     SendToServer_ContinuePlaying();
4885 #endif
4886
4887   /* restore deactivated drawing when quick-loading level tape recording */
4888   if (tape.playing && tape.deactivate_display)
4889     TapeDeactivateDisplayOn();
4890
4891   return result;
4892 }
4893
4894 static boolean RequestEnvelope(char *text, unsigned int req_state)
4895 {
4896   int result;
4897 #if 0
4898   int i;
4899 #endif
4900
4901   if (game_status == GAME_MODE_PLAYING)
4902   {
4903 #if 1
4904 #if 1
4905     BlitScreenToBitmap(backbuffer);
4906 #else
4907     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4908       BlitScreenToBitmap_EM(backbuffer);
4909     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4910       BlitScreenToBitmap_SP(backbuffer);
4911     else
4912       BlitScreenToBitmap_RND(backbuffer);
4913 #endif
4914 #else
4915     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4916       BlitScreenToBitmap_EM(backbuffer);
4917     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4918       BlitScreenToBitmap_SP(backbuffer);
4919 #endif
4920   }
4921
4922   /* disable deactivated drawing when quick-loading level tape recording */
4923   if (tape.playing && tape.deactivate_display)
4924     TapeDeactivateDisplayOff(TRUE);
4925
4926   SetMouseCursor(CURSOR_DEFAULT);
4927
4928 #if defined(NETWORK_AVALIABLE)
4929   /* pause network game while waiting for request to answer */
4930   if (options.network &&
4931       game_status == GAME_MODE_PLAYING &&
4932       req_state & REQUEST_WAIT_FOR_INPUT)
4933     SendToServer_PausePlaying();
4934 #endif
4935
4936   /* simulate releasing mouse button over last gadget, if still pressed */
4937   if (button_status)
4938     HandleGadgets(-1, -1, 0);
4939
4940   UnmapAllGadgets();
4941
4942   // (replace with setting corresponding request background)
4943   // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4944   // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4945
4946   /* clear door drawing field */
4947   // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4948
4949 #if 0
4950   if (global.use_envelope_request)
4951   {
4952     /* !!! TMP !!! */
4953     FreeToolButtons();
4954     CreateToolButtons();
4955   }
4956 #endif
4957
4958 #if 0
4959 #if 0
4960   if (req_state & REQ_ASK)
4961   {
4962     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4963     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4964   }
4965   else if (req_state & REQ_CONFIRM)
4966   {
4967     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4968   }
4969   else if (req_state & REQ_PLAYER)
4970   {
4971     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4972     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4973     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4974     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4975   }
4976 #else
4977   if (req_state & REQ_ASK)
4978   {
4979     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4980     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4981   }
4982   else if (req_state & REQ_CONFIRM)
4983   {
4984     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4985   }
4986   else if (req_state & REQ_PLAYER)
4987   {
4988     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4989     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4990     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4991     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4992   }
4993 #endif
4994 #endif
4995
4996   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4997
4998 #if 0
4999   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5000   {
5001     if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5002                                  i == TOOL_CTRL_ID_NO)) ||
5003         (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5004         (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5005                                     i == TOOL_CTRL_ID_PLAYER_2 &&
5006                                     i == TOOL_CTRL_ID_PLAYER_3 &&
5007                                     i == TOOL_CTRL_ID_PLAYER_4)))
5008     {
5009       int x = tool_gadget[i]->x + dDX;
5010       int y = tool_gadget[i]->y + dDY;
5011
5012       ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5013     }
5014   }
5015 #endif
5016
5017   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5018   {
5019     if (game_status == GAME_MODE_PLAYING)
5020     {
5021       SetPanelBackground();
5022       SetDrawBackgroundMask(REDRAW_DOOR_1);
5023     }
5024     else
5025     {
5026       SetDrawBackgroundMask(REDRAW_FIELD);
5027     }
5028
5029     return FALSE;
5030   }
5031
5032 #if 0
5033   if (game_status != GAME_MODE_MAIN)
5034     InitAnimation();
5035 #endif
5036
5037   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5038
5039   // ---------- handle request buttons ----------
5040   result = RequestHandleEvents(req_state);
5041
5042   if (game_status != GAME_MODE_MAIN)
5043     StopAnimation();
5044
5045   UnmapToolButtons();
5046
5047   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
5048
5049   RemapAllGadgets();
5050
5051   if (game_status == GAME_MODE_PLAYING)
5052   {
5053     SetPanelBackground();
5054     SetDrawBackgroundMask(REDRAW_DOOR_1);
5055   }
5056   else
5057   {
5058     SetDrawBackgroundMask(REDRAW_FIELD);
5059   }
5060
5061 #if defined(NETWORK_AVALIABLE)
5062   /* continue network game after request */
5063   if (options.network &&
5064       game_status == GAME_MODE_PLAYING &&
5065       req_state & REQUEST_WAIT_FOR_INPUT)
5066     SendToServer_ContinuePlaying();
5067 #endif
5068
5069   /* restore deactivated drawing when quick-loading level tape recording */
5070   if (tape.playing && tape.deactivate_display)
5071     TapeDeactivateDisplayOn();
5072
5073   return result;
5074 }
5075
5076 boolean Request(char *text, unsigned int req_state)
5077 {
5078   if (global.use_envelope_request)
5079     return RequestEnvelope(text, req_state);
5080   else
5081     return RequestDoor(text, req_state);
5082 }
5083
5084 #else   // =====================================================================
5085
5086 boolean Request(char *text, unsigned int req_state)
5087 {
5088   int mx, my, ty, result = -1;
5089   unsigned int old_door_state;
5090   int last_game_status = game_status;   /* save current game status */
5091   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
5092   int font_nr = FONT_TEXT_2;
5093 #if 0
5094   int max_word_len = 0;
5095 #endif
5096   char *text_ptr;
5097   int i;
5098
5099 #if 0
5100   global.use_envelope_request = 1;
5101 #endif
5102
5103 #if 1
5104   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
5105   {
5106     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5107     font_nr = FONT_TEXT_1;
5108   }
5109 #else
5110   for (text_ptr = text; *text_ptr; text_ptr++)
5111   {
5112     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
5113
5114     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
5115     {
5116       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
5117 #if 1
5118       font_nr = FONT_TEXT_1;
5119 #else
5120       font_nr = FONT_LEVEL_NUMBER;
5121 #endif
5122
5123       break;
5124     }
5125   }
5126 #endif
5127
5128   if (game_status == GAME_MODE_PLAYING)
5129   {
5130 #if 1
5131     BlitScreenToBitmap(backbuffer);
5132 #else
5133     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
5134       BlitScreenToBitmap_EM(backbuffer);
5135     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
5136       BlitScreenToBitmap_SP(backbuffer);
5137 #endif
5138   }
5139
5140   /* disable deactivated drawing when quick-loading level tape recording */
5141   if (tape.playing && tape.deactivate_display)
5142     TapeDeactivateDisplayOff(TRUE);
5143
5144   SetMouseCursor(CURSOR_DEFAULT);
5145
5146 #if defined(NETWORK_AVALIABLE)
5147   /* pause network game while waiting for request to answer */
5148   if (options.network &&
5149       game_status == GAME_MODE_PLAYING &&
5150       req_state & REQUEST_WAIT_FOR_INPUT)
5151     SendToServer_PausePlaying();
5152 #endif
5153
5154   old_door_state = GetDoorState();
5155
5156   /* simulate releasing mouse button over last gadget, if still pressed */
5157   if (button_status)
5158     HandleGadgets(-1, -1, 0);
5159
5160   UnmapAllGadgets();
5161
5162   /* draw released gadget before proceeding */
5163   // BackToFront();
5164
5165 #if 0
5166   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
5167 #else
5168   if (old_door_state & DOOR_OPEN_1)
5169 #endif
5170   {
5171 #if 1
5172     if (!global.use_envelope_request)
5173       CloseDoor(DOOR_CLOSE_1);
5174 #else
5175     CloseDoor(DOOR_CLOSE_1);
5176 #endif
5177
5178     /* save old door content */
5179     BlitBitmap(bitmap_db_door, bitmap_db_door,
5180                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5181                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
5182   }
5183
5184 #if 1
5185   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
5186 #endif
5187
5188   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5189
5190   /* clear door drawing field */
5191   DrawBackground(DX, DY, DXSIZE, DYSIZE);
5192
5193   /* force DOOR font inside door area */
5194   game_status = GAME_MODE_PSEUDO_DOOR;
5195
5196   /* write text for request */
5197   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5198   {
5199     char text_line[max_request_line_len + 1];
5200     int tx, tl, tc = 0;
5201
5202     if (!*text_ptr)
5203       break;
5204
5205     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5206     {
5207       tc = *(text_ptr + tx);
5208       if (!tc || tc == ' ')
5209         break;
5210     }
5211
5212     if (!tl)
5213     { 
5214       text_ptr++; 
5215       ty--; 
5216       continue; 
5217     }
5218
5219     strncpy(text_line, text_ptr, tl);
5220     text_line[tl] = 0;
5221
5222     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5223              DY + 8 + ty * (getFontHeight(font_nr) + 2),
5224              text_line, font_nr);
5225
5226     text_ptr += tl + (tc == ' ' ? 1 : 0);
5227   }
5228
5229   game_status = last_game_status;       /* restore current game status */
5230
5231 #if 1
5232   if (global.use_envelope_request)
5233   {
5234     /* !!! TMP !!! */
5235     FreeToolButtons();
5236     CreateToolButtons();
5237   }
5238 #endif
5239
5240   if (req_state & REQ_ASK)
5241   {
5242     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5243     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5244   }
5245   else if (req_state & REQ_CONFIRM)
5246   {
5247     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5248   }
5249   else if (req_state & REQ_PLAYER)
5250   {
5251     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5252     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5253     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5254     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5255   }
5256
5257   /* copy request gadgets to door backbuffer */
5258   BlitBitmap(drawto, bitmap_db_door,
5259              DX, DY, DXSIZE, DYSIZE,
5260              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5261
5262 #if 1
5263   if (global.use_envelope_request)
5264   {
5265     ShowEnvelopeRequest(text, ACTION_OPENING);
5266
5267     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5268     {
5269       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5270                                    i == TOOL_CTRL_ID_NO)) ||
5271           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5272           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5273                                       i == TOOL_CTRL_ID_PLAYER_2 &&
5274                                       i == TOOL_CTRL_ID_PLAYER_3 &&
5275                                       i == TOOL_CTRL_ID_PLAYER_4)))
5276       {
5277         int x = tool_gadget[i]->x + dDX;
5278         int y = tool_gadget[i]->y + dDY;
5279
5280         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5281       }
5282     }
5283   }
5284 #endif
5285
5286 #if 1
5287   if (!global.use_envelope_request)
5288     OpenDoor(DOOR_OPEN_1);
5289 #else
5290   OpenDoor(DOOR_OPEN_1);
5291 #endif
5292
5293   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5294   {
5295     if (game_status == GAME_MODE_PLAYING)
5296     {
5297       SetPanelBackground();
5298       SetDrawBackgroundMask(REDRAW_DOOR_1);
5299     }
5300     else
5301     {
5302       SetDrawBackgroundMask(REDRAW_FIELD);
5303     }
5304
5305     return FALSE;
5306   }
5307
5308 #if 1
5309   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5310     InitAnimation();
5311 #else
5312   if (game_status != GAME_MODE_MAIN)
5313     InitAnimation();
5314 #endif
5315
5316   button_status = MB_RELEASED;
5317
5318   request_gadget_id = -1;
5319
5320   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5321
5322   while (result < 0)
5323   {
5324     if (PendingEvent())
5325     {
5326       Event event;
5327
5328       NextEvent(&event);
5329
5330       switch (event.type)
5331       {
5332         case EVENT_BUTTONPRESS:
5333         case EVENT_BUTTONRELEASE:
5334         case EVENT_MOTIONNOTIFY:
5335         {
5336           if (event.type == EVENT_MOTIONNOTIFY)
5337           {
5338             if (!PointerInWindow(window))
5339               continue; /* window and pointer are on different screens */
5340
5341             if (!button_status)
5342               continue;
5343
5344             motion_status = TRUE;
5345             mx = ((MotionEvent *) &event)->x;
5346             my = ((MotionEvent *) &event)->y;
5347           }
5348           else
5349           {
5350             motion_status = FALSE;
5351             mx = ((ButtonEvent *) &event)->x;
5352             my = ((ButtonEvent *) &event)->y;
5353             if (event.type == EVENT_BUTTONPRESS)
5354               button_status = ((ButtonEvent *) &event)->button;
5355             else
5356               button_status = MB_RELEASED;
5357           }
5358
5359           /* this sets 'request_gadget_id' */
5360           HandleGadgets(mx, my, button_status);
5361
5362           switch (request_gadget_id)
5363           {
5364             case TOOL_CTRL_ID_YES:
5365               result = TRUE;
5366               break;
5367             case TOOL_CTRL_ID_NO:
5368               result = FALSE;
5369               break;
5370             case TOOL_CTRL_ID_CONFIRM:
5371               result = TRUE | FALSE;
5372               break;
5373
5374             case TOOL_CTRL_ID_PLAYER_1:
5375               result = 1;
5376               break;
5377             case TOOL_CTRL_ID_PLAYER_2:
5378               result = 2;
5379               break;
5380             case TOOL_CTRL_ID_PLAYER_3:
5381               result = 3;
5382               break;
5383             case TOOL_CTRL_ID_PLAYER_4:
5384               result = 4;
5385               break;
5386
5387             default:
5388               break;
5389           }
5390
5391           break;
5392         }
5393
5394         case EVENT_KEYPRESS:
5395           switch (GetEventKey((KeyEvent *)&event, TRUE))
5396           {
5397             case KSYM_space:
5398               if (req_state & REQ_CONFIRM)
5399                 result = 1;
5400               break;
5401
5402             case KSYM_Return:
5403               result = 1;
5404               break;
5405
5406             case KSYM_Escape:
5407 #if defined(TARGET_SDL2)
5408             case KSYM_Back:
5409 #endif
5410               result = 0;
5411               break;
5412
5413             default:
5414               break;
5415           }
5416
5417           if (req_state & REQ_PLAYER)
5418             result = 0;
5419           break;
5420
5421         case EVENT_KEYRELEASE:
5422           ClearPlayerAction();
5423           break;
5424
5425         default:
5426           HandleOtherEvents(&event);
5427           break;
5428       }
5429     }
5430     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5431     {
5432       int joy = AnyJoystick();
5433
5434       if (joy & JOY_BUTTON_1)
5435         result = 1;
5436       else if (joy & JOY_BUTTON_2)
5437         result = 0;
5438     }
5439
5440 #if 1
5441
5442     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5443     {
5444       HandleGameActions();
5445     }
5446     else
5447     {
5448       DoAnimation();
5449
5450       if (!PendingEvent())      /* delay only if no pending events */
5451         Delay(10);
5452     }
5453
5454 #if 1
5455     game_status = GAME_MODE_PSEUDO_DOOR;
5456 #endif
5457
5458     BackToFront();
5459
5460 #if 1
5461     game_status = last_game_status;     /* restore current game status */
5462 #endif
5463
5464 #else
5465
5466     DoAnimation();
5467
5468 #if 1
5469     if (!PendingEvent())        /* delay only if no pending events */
5470       Delay(10);
5471 #else
5472     /* don't eat all CPU time */
5473     Delay(10);
5474 #endif
5475
5476 #endif
5477   }
5478
5479   if (game_status != GAME_MODE_MAIN)
5480     StopAnimation();
5481
5482   UnmapToolButtons();
5483
5484 #if 1
5485   if (global.use_envelope_request)
5486     ShowEnvelopeRequest(text, ACTION_CLOSING);
5487 #endif
5488
5489 #if 1
5490   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5491 #else
5492   if (!(req_state & REQ_STAY_OPEN))
5493 #endif
5494   {
5495     CloseDoor(DOOR_CLOSE_1);
5496
5497     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5498         (req_state & REQ_REOPEN))
5499       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5500   }
5501
5502   RemapAllGadgets();
5503
5504   if (game_status == GAME_MODE_PLAYING)
5505   {
5506     SetPanelBackground();
5507     SetDrawBackgroundMask(REDRAW_DOOR_1);
5508   }
5509   else
5510   {
5511     SetDrawBackgroundMask(REDRAW_FIELD);
5512   }
5513
5514 #if defined(NETWORK_AVALIABLE)
5515   /* continue network game after request */
5516   if (options.network &&
5517       game_status == GAME_MODE_PLAYING &&
5518       req_state & REQUEST_WAIT_FOR_INPUT)
5519     SendToServer_ContinuePlaying();
5520 #endif
5521
5522   /* restore deactivated drawing when quick-loading level tape recording */
5523   if (tape.playing && tape.deactivate_display)
5524     TapeDeactivateDisplayOn();
5525
5526   return result;
5527 }
5528
5529 #endif
5530
5531 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5532 {
5533   const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5534   const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5535   int compare_result;
5536
5537   if (dpo1->sort_priority != dpo2->sort_priority)
5538     compare_result = dpo1->sort_priority - dpo2->sort_priority;
5539   else
5540     compare_result = dpo1->nr - dpo2->nr;
5541
5542   return compare_result;
5543 }
5544
5545 void InitGraphicCompatibilityInfo_Doors()
5546 {
5547   struct
5548   {
5549     int door_token;
5550     int part_1, part_8;
5551     struct DoorInfo *door;
5552   }
5553   doors[] =
5554   {
5555     { DOOR_1,   IMG_DOOR_1_GFX_PART_1,  IMG_DOOR_1_GFX_PART_8,  &door_1 },
5556     { DOOR_2,   IMG_DOOR_2_GFX_PART_1,  IMG_DOOR_2_GFX_PART_8,  &door_2 },
5557
5558     { -1,       -1,                     -1,                     NULL    }
5559   };
5560   struct Rect door_rect_list[] =
5561   {
5562     { DX, DY, DXSIZE, DYSIZE },
5563     { VX, VY, VXSIZE, VYSIZE }
5564   };
5565   int i, j;
5566
5567   for (i = 0; doors[i].door_token != -1; i++)
5568   {
5569     int door_token = doors[i].door_token;
5570     int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5571     int part_1 = doors[i].part_1;
5572     int part_8 = doors[i].part_8;
5573     int part_2 = part_1 + 1;
5574     int part_3 = part_1 + 2;
5575     struct DoorInfo *door = doors[i].door;
5576     struct Rect *door_rect = &door_rect_list[door_index];
5577     boolean door_gfx_redefined = FALSE;
5578
5579     /* check if any door part graphic definitions have been redefined */
5580
5581     for (j = 0; door_part_controls[j].door_token != -1; j++)
5582     {
5583       struct DoorPartControlInfo *dpc = &door_part_controls[j];
5584       struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5585
5586       if (dpc->door_token == door_token && fi->redefined)
5587         door_gfx_redefined = TRUE;
5588     }
5589
5590     /* check for old-style door graphic/animation modifications */
5591
5592     if (!door_gfx_redefined)
5593     {
5594       if (door->anim_mode & ANIM_STATIC_PANEL)
5595       {
5596         door->panel.step_xoffset = 0;
5597         door->panel.step_yoffset = 0;
5598       }
5599
5600       if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5601       {
5602         struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5603         struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5604         int num_door_steps, num_panel_steps;
5605
5606         /* remove door part graphics other than the two default wings */
5607
5608         for (j = 0; door_part_controls[j].door_token != -1; j++)
5609         {
5610           struct DoorPartControlInfo *dpc = &door_part_controls[j];
5611           struct GraphicInfo *g = &graphic_info[dpc->graphic];
5612
5613           if (dpc->graphic >= part_3 &&
5614               dpc->graphic <= part_8)
5615             g->bitmap = NULL;
5616         }
5617
5618         /* set graphics and screen positions of the default wings */
5619
5620         g_part_1->width  = door_rect->width;
5621         g_part_1->height = door_rect->height;
5622         g_part_2->width  = door_rect->width;
5623         g_part_2->height = door_rect->height;
5624         g_part_2->src_x = door_rect->width;
5625         g_part_2->src_y = g_part_1->src_y;
5626
5627         door->part_2.x = door->part_1.x;
5628         door->part_2.y = door->part_1.y;
5629
5630         if (door->width != -1)
5631         {
5632           g_part_1->width = door->width;
5633           g_part_2->width = door->width;
5634
5635           // special treatment for graphics and screen position of right wing
5636           g_part_2->src_x += door_rect->width - door->width;
5637           door->part_2.x  += door_rect->width - door->width;
5638         }
5639
5640         if (door->height != -1)
5641         {
5642           g_part_1->height = door->height;
5643           g_part_2->height = door->height;
5644
5645           // special treatment for graphics and screen position of bottom wing
5646           g_part_2->src_y += door_rect->height - door->height;
5647           door->part_2.y  += door_rect->height - door->height;
5648         }
5649
5650         /* set animation delays for the default wings and panels */
5651
5652         door->part_1.step_delay = door->step_delay;
5653         door->part_2.step_delay = door->step_delay;
5654         door->panel.step_delay  = door->step_delay;
5655
5656         /* set animation draw order for the default wings */
5657
5658         door->part_1.sort_priority = 2; /* draw left wing over ... */
5659         door->part_2.sort_priority = 1; /*          ... right wing */
5660
5661         /* set animation draw offset for the default wings */
5662
5663         if (door->anim_mode & ANIM_HORIZONTAL)
5664         {
5665           door->part_1.step_xoffset = door->step_offset;
5666           door->part_1.step_yoffset = 0;
5667           door->part_2.step_xoffset = door->step_offset * -1;
5668           door->part_2.step_yoffset = 0;
5669
5670           num_door_steps = g_part_1->width / door->step_offset;
5671         }
5672         else    // ANIM_VERTICAL
5673         {
5674           door->part_1.step_xoffset = 0;
5675           door->part_1.step_yoffset = door->step_offset;
5676           door->part_2.step_xoffset = 0;
5677           door->part_2.step_yoffset = door->step_offset * -1;
5678
5679           num_door_steps = g_part_1->height / door->step_offset;
5680         }
5681
5682         /* set animation draw offset for the default panels */
5683
5684         if (door->step_offset > 1)
5685         {
5686           num_panel_steps = 2 * door_rect->height / door->step_offset;
5687           door->panel.start_step = num_panel_steps - num_door_steps;
5688         }
5689         else
5690         {
5691           num_panel_steps = door_rect->height / door->step_offset;
5692           door->panel.start_step = num_panel_steps - num_door_steps / 2;
5693           door->panel.step_delay *= 2;
5694         }
5695       }
5696     }
5697   }
5698 }
5699
5700 void InitDoors()
5701 {
5702   int i;
5703
5704   for (i = 0; door_part_controls[i].door_token != -1; i++)
5705   {
5706     struct DoorPartControlInfo *dpc = &door_part_controls[i];
5707     struct DoorPartOrderInfo *dpo = &door_part_order[i];
5708
5709     /* initialize "start_step_opening" and "start_step_closing", if needed */
5710     if (dpc->pos->start_step_opening == 0 &&
5711         dpc->pos->start_step_closing == 0)
5712     {
5713       // dpc->pos->start_step_opening = dpc->pos->start_step;
5714       dpc->pos->start_step_closing = dpc->pos->start_step;
5715     }
5716
5717     /* fill structure for door part draw order (sorted below) */
5718     dpo->nr = i;
5719     dpo->sort_priority = dpc->pos->sort_priority;
5720
5721 #if 0
5722     struct DoorPartPosInfo *pos = dpc->pos;
5723
5724     printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5725            pos->step_xoffset, pos->step_yoffset);
5726 #endif
5727   }
5728
5729   /* sort door part controls according to sort_priority and graphic number */
5730   qsort(door_part_order, MAX_DOOR_PARTS,
5731         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5732 }
5733
5734 unsigned int OpenDoor(unsigned int door_state)
5735 {
5736   if (door_state & DOOR_COPY_BACK)
5737   {
5738 #if 1
5739     if (door_state & DOOR_OPEN_1)
5740       BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5741                  1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5742
5743     if (door_state & DOOR_OPEN_2)
5744       BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5745                  1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5746 #else
5747     if (door_state & DOOR_OPEN_1)
5748       BlitBitmap(bitmap_db_door, bitmap_db_door,
5749                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5750                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5751
5752     if (door_state & DOOR_OPEN_2)
5753       BlitBitmap(bitmap_db_door, bitmap_db_door,
5754                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5755                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5756 #endif
5757
5758     door_state &= ~DOOR_COPY_BACK;
5759   }
5760
5761   return MoveDoor(door_state);
5762 }
5763
5764 unsigned int CloseDoor(unsigned int door_state)
5765 {
5766   unsigned int old_door_state = GetDoorState();
5767
5768   if (!(door_state & DOOR_NO_COPY_BACK))
5769   {
5770 #if 1
5771     if (old_door_state & DOOR_OPEN_1)
5772       BlitBitmap(backbuffer, bitmap_db_door_1,
5773                  DX, DY, DXSIZE, DYSIZE, 0, 0);
5774
5775     if (old_door_state & DOOR_OPEN_2)
5776       BlitBitmap(backbuffer, bitmap_db_door_2,
5777                  VX, VY, VXSIZE, VYSIZE, 0, 0);
5778 #else
5779     if (old_door_state & DOOR_OPEN_1)
5780       BlitBitmap(backbuffer, bitmap_db_door,
5781                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5782
5783     if (old_door_state & DOOR_OPEN_2)
5784       BlitBitmap(backbuffer, bitmap_db_door,
5785                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5786 #endif
5787
5788     door_state &= ~DOOR_NO_COPY_BACK;
5789   }
5790
5791   return MoveDoor(door_state);
5792 }
5793
5794 unsigned int GetDoorState()
5795 {
5796   return MoveDoor(DOOR_GET_STATE);
5797 }
5798
5799 unsigned int SetDoorState(unsigned int door_state)
5800 {
5801   return MoveDoor(door_state | DOOR_SET_STATE);
5802 }
5803
5804 #if 1
5805
5806 // ========== TEST 1 ===========================================================
5807
5808 int euclid(int a, int b)
5809 {
5810   return (b ? euclid(b, a % b) : a);
5811 }
5812
5813 unsigned int MoveDoor(unsigned int door_state)
5814 {
5815 #if 0
5816   struct XY panel_pos_list[] =
5817   {
5818     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5819     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5820   };
5821 #endif
5822   struct Rect door_rect_list[] =
5823   {
5824     { DX, DY, DXSIZE, DYSIZE },
5825     { VX, VY, VXSIZE, VYSIZE }
5826   };
5827   static int door1 = DOOR_OPEN_1;
5828   static int door2 = DOOR_CLOSE_2;
5829   unsigned int door_delay = 0;
5830   unsigned int door_delay_value;
5831   int i;
5832
5833 #if 1
5834   if (door_1.width < 0 || door_1.width > DXSIZE)
5835     door_1.width = DXSIZE;
5836   if (door_1.height < 0 || door_1.height > DYSIZE)
5837     door_1.height = DYSIZE;
5838   if (door_2.width < 0 || door_2.width > VXSIZE)
5839     door_2.width = VXSIZE;
5840   if (door_2.height < 0 || door_2.height > VYSIZE)
5841     door_2.height = VYSIZE;
5842 #endif
5843
5844   if (door_state == DOOR_GET_STATE)
5845     return (door1 | door2);
5846
5847   if (door_state & DOOR_SET_STATE)
5848   {
5849     if (door_state & DOOR_ACTION_1)
5850       door1 = door_state & DOOR_ACTION_1;
5851     if (door_state & DOOR_ACTION_2)
5852       door2 = door_state & DOOR_ACTION_2;
5853
5854     return (door1 | door2);
5855   }
5856
5857   if (!(door_state & DOOR_FORCE_REDRAW))
5858   {
5859     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5860       door_state &= ~DOOR_OPEN_1;
5861     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5862       door_state &= ~DOOR_CLOSE_1;
5863     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5864       door_state &= ~DOOR_OPEN_2;
5865     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5866       door_state &= ~DOOR_CLOSE_2;
5867   }
5868
5869 #if 0
5870   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5871                       door_2.step_delay);
5872
5873   if (setup.quick_doors)
5874   {
5875     stepsize = 20;              /* must be chosen to always draw last frame */
5876     door_delay_value = 0;
5877   }
5878 #endif
5879
5880   if (global.autoplay_leveldir)
5881   {
5882     door_state |= DOOR_NO_DELAY;
5883     door_state &= ~DOOR_CLOSE_ALL;
5884   }
5885
5886 #if 1
5887   if (game_status == GAME_MODE_EDITOR)
5888     door_state |= DOOR_NO_DELAY;
5889 #endif
5890
5891   if (door_state & DOOR_ACTION)
5892   {
5893     boolean door_panel_drawn[NUM_DOORS];
5894     boolean panel_has_doors[NUM_DOORS];
5895     boolean door_part_skip[MAX_DOOR_PARTS];
5896     boolean door_part_done[MAX_DOOR_PARTS];
5897     boolean door_part_done_all;
5898     int num_steps[MAX_DOOR_PARTS];
5899     int max_move_delay = 0;     // delay for complete animations of all doors
5900     int max_step_delay = 0;     // delay (ms) between two animation frames
5901     int num_move_steps = 0;     // number of animation steps for all doors
5902     int current_move_delay = 0;
5903     int k;
5904
5905     for (i = 0; i < NUM_DOORS; i++)
5906       panel_has_doors[i] = FALSE;
5907
5908     for (i = 0; i < MAX_DOOR_PARTS; i++)
5909     {
5910       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5911       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5912       int door_token = dpc->door_token;
5913
5914       door_part_done[i] = FALSE;
5915       door_part_skip[i] = (!(door_state & door_token) ||
5916                            !g->bitmap);
5917     }
5918
5919 #if 0
5920     for (i = 0; i < MAX_DOOR_PARTS; i++)
5921     {
5922       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5923       struct DoorPartPosInfo *pos = dpc->pos;
5924       int start_step = pos->start_step;
5925
5926       printf("::: ---> %d: start_step == %d [%d]\n",
5927              i, start_step, door_part_done[i]);
5928     }
5929 #endif
5930
5931     for (i = 0; i < MAX_DOOR_PARTS; i++)
5932     {
5933       int nr = door_part_order[i].nr;
5934       struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5935       struct DoorPartPosInfo *pos = dpc->pos;
5936       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5937       int door_token = dpc->door_token;
5938       int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5939       boolean is_panel = DOOR_PART_IS_PANEL(nr);
5940       int step_xoffset = ABS(pos->step_xoffset);
5941       int step_yoffset = ABS(pos->step_yoffset);
5942       int step_delay = pos->step_delay;
5943       int current_door_state = door_state & door_token;
5944       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5945       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5946       boolean part_opening = (is_panel ? door_closing : door_opening);
5947       int start_step = (part_opening ? pos->start_step_opening :
5948                         pos->start_step_closing);
5949       float move_xsize = (step_xoffset ? g->width  : 0);
5950       float move_ysize = (step_yoffset ? g->height : 0);
5951       int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5952       int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5953       int move_steps = (move_xsteps && move_ysteps ?
5954                         MIN(move_xsteps, move_ysteps) :
5955                         move_xsteps ? move_xsteps : move_ysteps) - start_step;
5956       int move_delay = move_steps * step_delay;
5957
5958       if (door_part_skip[nr])
5959         continue;
5960
5961       if (!is_panel)
5962         panel_has_doors[door_index] = TRUE;
5963
5964       max_move_delay = MAX(max_move_delay, move_delay);
5965       max_step_delay = (max_step_delay == 0 ? step_delay :
5966                         euclid(max_step_delay, step_delay));
5967       num_steps[nr] = move_steps;
5968
5969 #if 0
5970 #if 0
5971       printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5972              i, move_delay, start_step, door_part_order[i].nr);
5973 #else
5974       if (DOOR_PART_IS_PANEL(i))
5975         printf("::: %d: move_delay == %d, start_step == %d\n",
5976                i, move_delay, start_step);
5977 #endif
5978 #endif
5979     }
5980
5981     num_move_steps = max_move_delay / max_step_delay;
5982
5983     door_delay_value = max_step_delay;
5984
5985 #if 0
5986     door_delay_value *= 10;
5987 #endif
5988
5989 #if 0
5990     printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5991 #endif
5992
5993     for (k = 0; k < num_move_steps; k++)
5994     {
5995       door_part_done_all = TRUE;
5996
5997       for (i = 0; i < NUM_DOORS; i++)
5998         door_panel_drawn[i] = FALSE;
5999
6000       for (i = 0; i < MAX_DOOR_PARTS; i++)
6001       {
6002         int nr = door_part_order[i].nr;
6003         struct DoorPartControlInfo *dpc = &door_part_controls[nr];
6004         struct DoorPartPosInfo *pos = dpc->pos;
6005         struct GraphicInfo *g = &graphic_info[dpc->graphic];
6006         int door_token = dpc->door_token;
6007         int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
6008         boolean is_panel = DOOR_PART_IS_PANEL(nr);
6009 #if 0
6010         struct XY *panel_pos = &panel_pos_list[door_index];
6011 #endif
6012         struct Rect *door_rect = &door_rect_list[door_index];
6013         Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
6014                                   bitmap_db_door_2);
6015         Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
6016         int current_door_state = door_state & door_token;
6017         boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
6018         boolean door_closing = !door_opening;
6019         boolean part_opening = (is_panel ? door_closing : door_opening);
6020         boolean part_closing = !part_opening;
6021         int start_step = (part_opening ? pos->start_step_opening :
6022                           pos->start_step_closing);
6023         int step_delay = pos->step_delay;
6024         int step_factor = step_delay / max_step_delay;
6025         int k1 = (step_factor ? k / step_factor + 1 : k);
6026         int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
6027         int kk = (k2 < 0 ? 0 : k2);
6028         int src_x, src_y, src_xx, src_yy;
6029         int dst_x, dst_y, dst_xx, dst_yy;
6030         int width, height;
6031
6032 #if 0
6033         if (k == 0 && is_panel && door_token == DOOR_2)
6034           printf("::: %d, %d\n", g->width, g->height);
6035 #endif
6036
6037 #if 0
6038         if (DOOR_PART_IS_PANEL(nr))
6039         {
6040           int start_step = pos->start_step;
6041
6042           k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
6043           kk = (k2 < 0 ? 0 : k2);
6044         }
6045 #endif
6046
6047 #if 0
6048         // !!! TEST !!! 
6049         if (nr != 16 && nr != 0)
6050           continue;
6051 #endif
6052
6053 #if 0
6054         // !!! TEST !!! 
6055         if (!is_panel)
6056           continue;
6057 #endif
6058
6059 #if 1
6060         if (door_part_skip[nr])
6061           continue;
6062 #endif
6063
6064         if (!(door_state & door_token))
6065           continue;
6066
6067         if (!g->bitmap)
6068           continue;
6069
6070 #if 0
6071         if (current_move_delay % step_delay)
6072           continue;
6073 #endif
6074
6075         // draw door panel
6076
6077         if (!door_panel_drawn[door_index])
6078         {
6079 #if 1
6080           ClearRectangle(drawto, door_rect->x, door_rect->y,
6081                          door_rect->width, door_rect->height);
6082 #else
6083           BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
6084                      door_rect->width, door_rect->height,
6085                      door_rect->x, door_rect->y);
6086 #endif
6087
6088           door_panel_drawn[door_index] = TRUE;
6089         }
6090
6091         // draw opening or closing door parts
6092
6093         if (pos->step_xoffset < 0)      // door part on right side
6094         {
6095           src_xx = 0;
6096           dst_xx = pos->x + ABS(kk * pos->step_xoffset);
6097           width = g->width;
6098
6099           if (dst_xx + width > door_rect->width)
6100             width = door_rect->width - dst_xx;
6101         }
6102         else                            // door part on left side
6103         {
6104           src_xx = 0;
6105           dst_xx = pos->x - kk * pos->step_xoffset;
6106
6107           if (dst_xx < 0)
6108           {
6109             src_xx = ABS(dst_xx);
6110             dst_xx = 0;
6111           }
6112
6113           width = g->width - src_xx;
6114
6115           // printf("::: k == %d [%d] \n", k, start_step);
6116         }
6117
6118         if (pos->step_yoffset < 0)      // door part on bottom side
6119         {
6120           src_yy = 0;
6121           dst_yy = pos->y + ABS(kk * pos->step_yoffset);
6122           height = g->height;
6123
6124           if (dst_yy + height > door_rect->height)
6125             height = door_rect->height - dst_yy;
6126         }
6127         else                            // door part on top side
6128         {
6129           src_yy = 0;
6130           dst_yy = pos->y - kk * pos->step_yoffset;
6131
6132           if (dst_yy < 0)
6133           {
6134             src_yy = ABS(dst_yy);
6135             dst_yy = 0;
6136           }
6137
6138           height = g->height - src_yy;
6139         }
6140
6141         if (is_panel)
6142         {
6143 #if 1
6144           src_x = src_xx;
6145           src_y = src_yy;
6146 #else
6147           src_x = panel_pos->x + src_xx;
6148           src_y = panel_pos->y + src_yy;
6149 #endif
6150         }
6151         else
6152         {
6153           src_x = g->src_x + src_xx;
6154           src_y = g->src_y + src_yy;
6155         }
6156
6157         dst_x = door_rect->x + dst_xx;
6158         dst_y = door_rect->y + dst_yy;
6159
6160 #if 0
6161         if (DOOR_PART_IS_PANEL(nr))
6162         {
6163           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6164                  width, height, g->width, g->height, src_x, src_y);
6165         }
6166 #endif
6167
6168         if (width  >= 0 && width  <= g->width &&
6169             height >= 0 && height <= g->height)
6170         {
6171           if (is_panel || !pos->draw_masked)
6172             BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
6173                        dst_x, dst_y);
6174           else
6175             BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
6176                              dst_x, dst_y);
6177         }
6178
6179 #if 0
6180         if (DOOR_PART_IS_PANEL(nr))
6181         {
6182           bitmap = bitmap_db_door;
6183           src_x = panel_pos->x + src_xx;
6184           src_y = panel_pos->y + src_yy;
6185
6186           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
6187                  width, height, g->width, g->height, src_x, src_y);
6188
6189           if (width  >= 0 && width  <= g->width &&
6190               height >= 0 && height <= g->height)
6191             BlitBitmap(bitmap, drawto, src_x, src_y,
6192                              width, height,
6193                              dst_x, dst_y);
6194         }
6195 #endif
6196
6197         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6198
6199 #if 1
6200         if ((part_opening && (width < 0         || height < 0)) ||
6201             (part_closing && (width >= g->width && height >= g->height)))
6202           door_part_done[nr] = TRUE;
6203 #else
6204         if ((door_opening && (width < 0         || height < 0)) ||
6205             (door_closing && (width >= g->width && height >= g->height)))
6206           door_part_done[nr] = TRUE;
6207 #endif
6208
6209 #if 1
6210         // continue door part animations, but not panel after door has closed
6211         if (!door_part_done[nr] &&
6212             !(is_panel && door_closing && panel_has_doors[door_index]))
6213           door_part_done_all = FALSE;
6214 #else
6215         // continue door part animations, but not panel after door has closed
6216         if (!door_part_done[nr] && !(is_panel && door_closing))
6217           door_part_done_all = FALSE;
6218 #endif
6219
6220 #if 0
6221         if (!door_part_done[nr])
6222           printf("::: k == %d, nr == %d\n", k, nr);
6223 #endif
6224       }
6225
6226       if (!(door_state & DOOR_NO_DELAY))
6227       {
6228         BackToFront();
6229
6230         if (game_status == GAME_MODE_MAIN)
6231           DoAnimation();
6232
6233         WaitUntilDelayReached(&door_delay, door_delay_value);
6234
6235         current_move_delay += max_step_delay;
6236       }
6237
6238 #if 0
6239       door_part_done_all = TRUE;
6240
6241       for (i = 0; i < MAX_DOOR_PARTS; i++)
6242         if (!door_part_done[i] &&
6243             !(DOOR_PART_IS_PANEL(i) && door_closing))
6244           door_part_done_all = FALSE;
6245 #endif
6246 #if 1
6247       if (door_part_done_all)
6248         break;
6249 #endif
6250     }
6251   }
6252
6253   if (door_state & DOOR_ACTION_1)
6254     door1 = door_state & DOOR_ACTION_1;
6255   if (door_state & DOOR_ACTION_2)
6256     door2 = door_state & DOOR_ACTION_2;
6257
6258 #if 0
6259   printf("::: DOORS DONE %08x\n", door_state);
6260   Delay(3000);
6261   printf("::: GO!\n");
6262 #endif
6263
6264   return (door1 | door2);
6265 }
6266
6267 #else
6268
6269 // ========== OLD ==============================================================
6270
6271 unsigned int MoveDoor(unsigned int door_state)
6272 {
6273   static int door1 = DOOR_OPEN_1;
6274   static int door2 = DOOR_CLOSE_2;
6275   unsigned int door_delay = 0;
6276   unsigned int door_delay_value;
6277   int stepsize = 1;
6278
6279 #if 1
6280   if (door_1.width < 0 || door_1.width > DXSIZE)
6281     door_1.width = DXSIZE;
6282   if (door_1.height < 0 || door_1.height > DYSIZE)
6283     door_1.height = DYSIZE;
6284   if (door_2.width < 0 || door_2.width > VXSIZE)
6285     door_2.width = VXSIZE;
6286   if (door_2.height < 0 || door_2.height > VYSIZE)
6287     door_2.height = VYSIZE;
6288 #endif
6289
6290   if (door_state == DOOR_GET_STATE)
6291     return (door1 | door2);
6292
6293   if (door_state & DOOR_SET_STATE)
6294   {
6295     if (door_state & DOOR_ACTION_1)
6296       door1 = door_state & DOOR_ACTION_1;
6297     if (door_state & DOOR_ACTION_2)
6298       door2 = door_state & DOOR_ACTION_2;
6299
6300     return (door1 | door2);
6301   }
6302
6303   if (!(door_state & DOOR_FORCE_REDRAW))
6304   {
6305     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6306       door_state &= ~DOOR_OPEN_1;
6307     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6308       door_state &= ~DOOR_CLOSE_1;
6309     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6310       door_state &= ~DOOR_OPEN_2;
6311     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6312       door_state &= ~DOOR_CLOSE_2;
6313   }
6314
6315   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6316                       door_2.step_delay);
6317
6318   // door_delay_value *= 4;     // !!! TEST ONLY !!!
6319
6320   if (setup.quick_doors)
6321   {
6322     stepsize = 20;              /* must be chosen to always draw last frame */
6323     door_delay_value = 0;
6324   }
6325
6326   if (global.autoplay_leveldir)
6327   {
6328     door_state |= DOOR_NO_DELAY;
6329     door_state &= ~DOOR_CLOSE_ALL;
6330   }
6331
6332 #if 1
6333   if (game_status == GAME_MODE_EDITOR)
6334     door_state |= DOOR_NO_DELAY;
6335 #endif
6336
6337   if (door_state & DOOR_ACTION)
6338   {
6339 #if 1
6340     struct GraphicInfo *g1_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6341     struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6342     struct GraphicInfo *g2_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6343     struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6344     int door_1_left_width   = g1_left->width;
6345     int door_1_left_height  = g1_left->height;
6346     int door_1_right_width  = g1_right->width;
6347     int door_1_right_height = g1_right->height;
6348     int door_2_left_width   = g2_left->width;
6349     int door_2_left_height  = g2_left->height;
6350     int door_2_right_width  = g2_right->width;
6351     int door_2_right_height = g2_right->height;
6352     int door_1_width  = MAX(door_1_left_width,  door_1_right_width);
6353     int door_1_height = MAX(door_1_left_height, door_1_right_height);
6354     int door_2_width  = MAX(door_2_left_width,  door_2_right_width);
6355     int door_2_height = MAX(door_2_left_height, door_2_right_height);
6356 #endif
6357     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6358     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6359     boolean door_1_done = (!handle_door_1);
6360     boolean door_2_done = (!handle_door_2);
6361     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6362     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6363 #if 1
6364 #if 1
6365     int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6366     int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6367 #else
6368     int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6369     int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6370 #endif
6371 #else
6372     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6373     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6374 #endif
6375     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6376     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6377     // int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
6378     int door_size     = (handle_door_2 ? door_size_2     : door_size_1);
6379     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6380     int door_skip = max_door_size - door_size;
6381     int end = door_size;
6382     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6383     int k;
6384
6385     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6386     {
6387       /* opening door sound has priority over simultaneously closing door */
6388       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6389         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6390       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6391         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6392     }
6393
6394     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6395     {
6396       int x = k;
6397 #if 0
6398       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6399       GC gc = bitmap->stored_clip_gc;
6400 #endif
6401
6402       if (door_state & DOOR_ACTION_1 &&
6403           x * door_1.step_offset <= door_size_1)
6404       {
6405         int a = MIN(x * door_1.step_offset, end);
6406         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6407 #if 1
6408         int i = p;
6409 #else
6410         int i = p + door_skip;
6411 #endif
6412
6413 #if 1
6414         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6415         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6416         Bitmap *bm_left  = g_left->bitmap;
6417         Bitmap *bm_right = g_right->bitmap;
6418         GC gc_left  = bm_left->stored_clip_gc;
6419         GC gc_right = bm_right->stored_clip_gc;
6420 #endif
6421
6422         int classic_dxsize = 100;
6423         int classic_dysize = 280;
6424         boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6425                                        DYSIZE == classic_dysize);
6426
6427         if (door_1.anim_mode & ANIM_STATIC_PANEL)
6428         {
6429           BlitBitmap(bitmap_db_door, drawto,
6430                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6431                      DXSIZE, DYSIZE, DX, DY);
6432         }
6433         else if (x <= a)
6434         {
6435           BlitBitmap(bitmap_db_door, drawto,
6436                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6437                      DXSIZE, DYSIZE - p / 2, DX, DY);
6438
6439 #if 1
6440           // printf("::: p == %d\n", p);
6441           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6442 #endif
6443         }
6444
6445         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6446         {
6447 #if 1
6448           int src1_x = g_right->src_x;
6449           int src1_y = g_right->src_y;
6450           int src2_x = g_left->src_x + g_left->width - i;
6451           int src2_y = g_left->src_y;
6452           int dst1_x = DX + DXSIZE - i;
6453           int dst1_y = DY;
6454           int dst2_x = DX;
6455           int dst2_y = DY;
6456           int width = i;
6457           int height = DYSIZE;
6458
6459           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6460           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6461                            dst1_x, dst1_y);
6462
6463           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6464           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6465                            dst2_x, dst2_y);
6466 #else
6467           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6468           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6469           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6470           int dst2_x = DX,              dst2_y = DY;
6471           int width = i, height = DYSIZE;
6472
6473           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6474           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6475                            dst1_x, dst1_y);
6476
6477           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6478           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6479                            dst2_x, dst2_y);
6480 #endif
6481         }
6482         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6483         {
6484 #if 1
6485           int src1_x = g_right->src_x;
6486           int src1_y = g_right->src_y;
6487           int src2_x = g_left->src_x;
6488           int src2_y = g_left->src_y + g_left->height - i;
6489           int dst1_x = DX;
6490           int dst1_y = DY + DYSIZE - i;
6491           int dst2_x = DX;
6492           int dst2_y = DY;
6493           int width = DXSIZE;
6494           int height = i;
6495
6496           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6497           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6498                            dst1_x, dst1_y);
6499
6500           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6501           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6502                            dst2_x, dst2_y);
6503 #else
6504           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6505           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6506           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
6507           int dst2_x = DX,              dst2_y = DY;
6508           int width = DXSIZE, height = i;
6509
6510           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6511           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6512                            dst1_x, dst1_y);
6513
6514           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6515           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6516                            dst2_x, dst2_y);
6517 #endif
6518         }
6519         else if (classic_door_1_size && x <= DXSIZE)    /* ANIM_DEFAULT */
6520         {
6521           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6522
6523 #if 1
6524           int src1_x = g_right->src_x;
6525           int src1_y = g_right->src_y;
6526           int src2_x = g_left->src_x + g_left->width - i;
6527           int src2_y = g_left->src_y;
6528           int dst1_x = DX + DXSIZE - i;
6529           int dst1_y = DY;
6530           int dst2_x = DX;
6531           int dst2_y = DY;
6532           int width = i;
6533           int height1 = 63, height2 = DYSIZE / 2 - height1;
6534           int ypos1 = 0, ypos2 = height2;
6535           int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6536
6537           SetClipOrigin(bm_right, gc_right,
6538                         dst1_x - src1_x, dst1_y - src1_y + j);
6539           BlitBitmapMasked(bm_right, drawto,
6540                            src1_x, src1_y + ypos1, width, height2,
6541                            dst1_x, dst1_y + ypos1 + j);
6542           BlitBitmapMasked(bm_right, drawto,
6543                            src1_x, src1_y + ypos3, width, height1,
6544                            dst1_x, dst1_y + ypos3 + j);
6545           SetClipOrigin(bm_left, gc_left,
6546                         dst2_x - src2_x, dst2_y - src2_y - j);
6547           BlitBitmapMasked(bm_left, drawto,
6548                            src2_x, src2_y + ypos1 + j, width, height2 - j,
6549                            dst2_x, dst2_y + ypos1);
6550           BlitBitmapMasked(bm_left, drawto,
6551                            src2_x, src2_y + ypos3, width, height1,
6552                            dst2_x, dst2_y + ypos3 - j);
6553
6554           SetClipOrigin(bm_left, gc_left,
6555                         dst2_x - src2_x, dst2_y - src2_y - j);
6556           BlitBitmapMasked(bm_left, drawto,
6557                            src2_x, src2_y + ypos2, width, height1,
6558                            dst2_x, dst2_y + ypos2 - j);
6559           BlitBitmapMasked(bm_left, drawto,
6560                            src2_x, src2_y + ypos4, width, height2,
6561                            dst2_x, dst2_y + ypos4 - j);
6562           SetClipOrigin(bm_right, gc_right,
6563                         dst1_x - src1_x, dst1_y - src1_y + j);
6564           BlitBitmapMasked(bm_right, drawto,
6565                            src1_x, src1_y + ypos2, width, height1,
6566                            dst1_x, dst1_y + ypos2 + j);
6567           BlitBitmapMasked(bm_right, drawto,
6568                            src1_x, src1_y + ypos4, width, height2 - j,
6569                            dst1_x, dst1_y + ypos4 + j);
6570
6571 #else
6572           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6573           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6574           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6575           int dst2_x = DX,              dst2_y = DY;
6576           int width = i, height = DYSIZE;
6577           int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6578
6579           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6580           BlitBitmapMasked(bitmap, drawto,
6581                            src1_x, src1_y, width, ypos2,
6582                            dst1_x, dst1_y + j);
6583           BlitBitmapMasked(bitmap, drawto,
6584                            src1_x, src1_y + ypos3, width, ypos1,
6585                            dst1_x, dst1_y + ypos3 + j);
6586           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6587           BlitBitmapMasked(bitmap, drawto,
6588                            src2_x, src2_y + j, width, ypos2 - j,
6589                            dst2_x, dst2_y);
6590           BlitBitmapMasked(bitmap, drawto,
6591                            src2_x, src2_y + ypos3, width, ypos1,
6592                            dst2_x, dst2_y + ypos3 - j);
6593
6594           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6595           BlitBitmapMasked(bitmap, drawto,
6596                            src2_x, src2_y + ypos2, width, ypos1,
6597                            dst2_x, dst2_y + ypos2 - j);
6598           BlitBitmapMasked(bitmap, drawto,
6599                            src2_x, src2_y + ypos4, width, ypos2,
6600                            dst2_x, dst2_y + ypos4 - j);
6601           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6602           BlitBitmapMasked(bitmap, drawto,
6603                            src1_x, src1_y + ypos2, width, ypos1,
6604                            dst1_x, dst1_y + ypos2 + j);
6605           BlitBitmapMasked(bitmap, drawto,
6606                            src1_x, src1_y + ypos4, width, ypos2 - j,
6607                            dst1_x, dst1_y + ypos4 + j);
6608
6609           /*
6610           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6611           BlitBitmapMasked(bitmap, drawto,
6612                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6613                            DX + DXSIZE - i, DY + j);
6614           BlitBitmapMasked(bitmap, drawto,
6615                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6616                            DX + DXSIZE - i, DY + 140 + j);
6617           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6618                         DY - (DOOR_GFX_PAGEY1 + j));
6619           BlitBitmapMasked(bitmap, drawto,
6620                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6621                            DX, DY);
6622           BlitBitmapMasked(bitmap, drawto,
6623                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6624                            DX, DY + 140 - j);
6625
6626           BlitBitmapMasked(bitmap, drawto,
6627                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6628                            DX, DY + 77 - j);
6629           BlitBitmapMasked(bitmap, drawto,
6630                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6631                            DX, DY + 203 - j);
6632           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6633           BlitBitmapMasked(bitmap, drawto,
6634                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6635                            DX + DXSIZE - i, DY + 77 + j);
6636           BlitBitmapMasked(bitmap, drawto,
6637                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6638                            DX + DXSIZE - i, DY + 203 + j);
6639           */
6640 #endif
6641         }
6642
6643         redraw_mask |= REDRAW_DOOR_1;
6644         door_1_done = (a == end);
6645       }
6646
6647       if (door_state & DOOR_ACTION_2 &&
6648           x * door_2.step_offset <= door_size_2)
6649       {
6650         int a = MIN(x * door_2.step_offset, door_size);
6651         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6652         int i = p + door_skip;
6653
6654 #if 1
6655         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6656         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6657         Bitmap *bm_left  = g_left->bitmap;
6658         Bitmap *bm_right = g_right->bitmap;
6659         GC gc_left  = bm_left->stored_clip_gc;
6660         GC gc_right = bm_right->stored_clip_gc;
6661 #endif
6662
6663         int classic_vxsize = 100;
6664         int classic_vysize = 100;
6665         boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6666                                        VYSIZE == classic_vysize);
6667
6668         if (door_2.anim_mode & ANIM_STATIC_PANEL)
6669         {
6670           BlitBitmap(bitmap_db_door, drawto,
6671                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6672                      VXSIZE, VYSIZE, VX, VY);
6673         }
6674         else if (x <= VYSIZE)
6675         {
6676           BlitBitmap(bitmap_db_door, drawto,
6677                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6678                      VXSIZE, VYSIZE - p / 2, VX, VY);
6679
6680           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6681         }
6682
6683         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6684         {
6685 #if 1
6686           int src1_x = g_right->src_x;
6687           int src1_y = g_right->src_y;
6688           int src2_x = g_left->src_x + g_left->width - i;
6689           int src2_y = g_left->src_y;
6690           int dst1_x = VX + VXSIZE - i;
6691           int dst1_y = VY;
6692           int dst2_x = VX;
6693           int dst2_y = VY;
6694           int width = i;
6695           int height = VYSIZE;
6696
6697           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6698           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6699                            dst1_x, dst1_y);
6700
6701           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6702           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6703                            dst2_x, dst2_y);
6704 #else
6705           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6706           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6707           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6708           int dst2_x = VX,              dst2_y = VY;
6709           int width = i, height = VYSIZE;
6710
6711           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6712           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6713                            dst1_x, dst1_y);
6714
6715           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6716           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6717                            dst2_x, dst2_y);
6718 #endif
6719         }
6720         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6721         {
6722 #if 1
6723           int src1_x = g_right->src_x;
6724           int src1_y = g_right->src_y;
6725           int src2_x = g_left->src_x;
6726           int src2_y = g_left->src_y + g_left->height - i;
6727           int dst1_x = VX;
6728           int dst1_y = VY + VYSIZE - i;
6729           int dst2_x = VX;
6730           int dst2_y = VY;
6731           int width = VXSIZE;
6732           int height = i;
6733
6734           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6735           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6736                            dst1_x, dst1_y);
6737
6738           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6739           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6740                            dst2_x, dst2_y);
6741 #else
6742           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6743           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6744           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
6745           int dst2_x = VX,              dst2_y = VY;
6746           int width = VXSIZE, height = i;
6747
6748           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6749           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6750                            dst1_x, dst1_y);
6751
6752           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6753           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6754                            dst2_x, dst2_y);
6755 #endif
6756         }
6757         else if (classic_door_2_size && x <= VXSIZE)    /* ANIM_DEFAULT */
6758         {
6759           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6760
6761 #if 1
6762           int src1_x = g_right->src_x;
6763           int src1_y = g_right->src_y;
6764           int src2_x = g_left->src_x + g_left->width - i;
6765           int src2_y = g_left->src_y;
6766           int dst1_x = VX + VXSIZE - i;
6767           int dst1_y = VY;
6768           int dst2_x = VX;
6769           int dst2_y = VY;
6770           int width = i;
6771           int height = VYSIZE / 2;
6772           int ypos1 = 0, ypos2 = VYSIZE / 2;
6773
6774           SetClipOrigin(bm_right, gc_right,
6775                         dst1_x - src1_x, dst1_y - src1_y + j);
6776           BlitBitmapMasked(bm_right, drawto,
6777                            src1_x, src1_y + ypos1, width, height,
6778                            dst1_x, dst1_y + ypos1 + j);
6779           SetClipOrigin(bm_left, gc_left,
6780                         dst2_x - src2_x, dst2_y - src2_y - j);
6781           BlitBitmapMasked(bm_left, drawto,
6782                            src2_x, src2_y + ypos1 + j, width, height - j,
6783                            dst2_x, dst2_y + ypos1);
6784
6785           SetClipOrigin(bm_left, gc_left,
6786                         dst2_x - src2_x, dst2_y - src2_y - j);
6787           BlitBitmapMasked(bm_left, drawto,
6788                            src2_x, src2_y + ypos2, width, height,
6789                            dst2_x, dst2_y + ypos2 - j);
6790           SetClipOrigin(bm_right, gc_right,
6791                         dst1_x - src1_x, dst1_y - src1_y + j);
6792           BlitBitmapMasked(bm_right, drawto,
6793                            src1_x, src1_y + ypos2, width, height - j,
6794                            dst1_x, dst1_y + ypos2 + j);
6795 #else
6796           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6797           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6798           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6799           int dst2_x = VX,              dst2_y = VY;
6800           int width = i, height = VYSIZE;
6801           int ypos = VYSIZE / 2;
6802
6803           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6804           BlitBitmapMasked(bitmap, drawto,
6805                            src1_x, src1_y, width, ypos,
6806                            dst1_x, dst1_y + j);
6807           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6808           BlitBitmapMasked(bitmap, drawto,
6809                            src2_x, src2_y + j, width, ypos - j,
6810                            dst2_x, dst2_y);
6811
6812           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6813           BlitBitmapMasked(bitmap, drawto,
6814                            src2_x, src2_y + ypos, width, ypos,
6815                            dst2_x, dst2_y + ypos - j);
6816           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6817           BlitBitmapMasked(bitmap, drawto,
6818                            src1_x, src1_y + ypos, width, ypos - j,
6819                            dst1_x, dst1_y + ypos + j);
6820
6821           /*
6822           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6823           BlitBitmapMasked(bitmap, drawto,
6824                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6825                            VX + VXSIZE - i, VY + j);
6826           SetClipOrigin(bitmap, gc,
6827                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6828           BlitBitmapMasked(bitmap, drawto,
6829                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6830                            VX, VY);
6831
6832           BlitBitmapMasked(bitmap, drawto,
6833                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6834                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6835           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6836           BlitBitmapMasked(bitmap, drawto,
6837                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6838                            i, VYSIZE / 2 - j,
6839                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6840           */
6841 #endif
6842         }
6843
6844         redraw_mask |= REDRAW_DOOR_2;
6845         door_2_done = (a == VXSIZE);
6846       }
6847
6848       if (!(door_state & DOOR_NO_DELAY))
6849       {
6850         BackToFront();
6851
6852         if (game_status == GAME_MODE_MAIN)
6853           DoAnimation();
6854
6855         WaitUntilDelayReached(&door_delay, door_delay_value);
6856       }
6857     }
6858   }
6859
6860   if (door_state & DOOR_ACTION_1)
6861     door1 = door_state & DOOR_ACTION_1;
6862   if (door_state & DOOR_ACTION_2)
6863     door2 = door_state & DOOR_ACTION_2;
6864
6865   return (door1 | door2);
6866 }
6867
6868 #endif
6869
6870 void DrawSpecialEditorDoor()
6871 {
6872 #if 1
6873   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6874   int top_border_width = gfx1->width;
6875   int top_border_height = gfx1->height;
6876   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6877   int ex = EX - outer_border;
6878   int ey = EY - outer_border;
6879   int vy = VY - outer_border;
6880   int exsize = EXSIZE + 2 * outer_border;
6881
6882   CloseDoor(DOOR_CLOSE_2);
6883
6884   /* draw bigger level editor toolbox window */
6885   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6886              top_border_width, top_border_height, ex, ey - top_border_height);
6887   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6888              exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6889 #else
6890   /* draw bigger level editor toolbox window */
6891   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6892              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6893              EX - 4, EY - 12);
6894   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6895              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6896              EX - 6, EY - 4);
6897 #endif
6898
6899   redraw_mask |= REDRAW_ALL;
6900 }
6901
6902 void UndrawSpecialEditorDoor()
6903 {
6904 #if 1
6905   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6906   int top_border_width = gfx1->width;
6907   int top_border_height = gfx1->height;
6908   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6909   int ex = EX - outer_border;
6910   int ey = EY - outer_border;
6911   int ey_top = ey - top_border_height;
6912   int exsize = EXSIZE + 2 * outer_border;
6913   int eysize = EYSIZE + 2 * outer_border;
6914
6915   /* draw normal tape recorder window */
6916   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6917   {
6918     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6919                ex, ey_top, top_border_width, top_border_height,
6920                ex, ey_top);
6921     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6922                ex, ey, exsize, eysize, ex, ey);
6923   }
6924   else
6925   {
6926     // if screen background is set to "[NONE]", clear editor toolbox window
6927     ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6928     ClearRectangle(drawto, ex, ey, exsize, eysize);
6929   }
6930 #else
6931   /* draw normal tape recorder window */
6932   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6933              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6934              EX - 6, EY - 12);
6935 #endif
6936
6937   redraw_mask |= REDRAW_ALL;
6938 }
6939
6940
6941 /* ---------- new tool button stuff ---------------------------------------- */
6942
6943 #if 1
6944
6945 static struct
6946 {
6947   int graphic;
6948   struct TextPosInfo *pos;
6949   int gadget_id;
6950   char *infotext;
6951 } toolbutton_info[NUM_TOOL_BUTTONS] =
6952 {
6953   {
6954     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
6955     TOOL_CTRL_ID_YES,                   "yes"
6956   },
6957   {
6958     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
6959     TOOL_CTRL_ID_NO,                    "no"
6960   },
6961   {
6962     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
6963     TOOL_CTRL_ID_CONFIRM,               "confirm"
6964   },
6965   {
6966     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
6967     TOOL_CTRL_ID_PLAYER_1,              "player 1"
6968   },
6969   {
6970     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
6971     TOOL_CTRL_ID_PLAYER_2,              "player 2"
6972   },
6973   {
6974     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
6975     TOOL_CTRL_ID_PLAYER_3,              "player 3"
6976   },
6977   {
6978     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
6979     TOOL_CTRL_ID_PLAYER_4,              "player 4"
6980   }
6981 };
6982
6983 void CreateToolButtons()
6984 {
6985   int i;
6986
6987   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6988   {
6989     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6990     struct TextPosInfo *pos = toolbutton_info[i].pos;
6991     struct GadgetInfo *gi;
6992     Bitmap *deco_bitmap = None;
6993     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6994     unsigned int event_mask = GD_EVENT_RELEASED;
6995     int dx = DX;
6996     int dy = DY;
6997     int gd_x = gfx->src_x;
6998     int gd_y = gfx->src_y;
6999     int gd_xp = gfx->src_x + gfx->pressed_xoffset;
7000     int gd_yp = gfx->src_y + gfx->pressed_yoffset;
7001     int id = i;
7002
7003     if (global.use_envelope_request)
7004       setRequestPosition(&dx, &dy, TRUE);
7005
7006     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7007     {
7008       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7009
7010       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
7011                             pos->size, &deco_bitmap, &deco_x, &deco_y);
7012       deco_xpos = (gfx->width  - pos->size) / 2;
7013       deco_ypos = (gfx->height - pos->size) / 2;
7014     }
7015
7016     gi = CreateGadget(GDI_CUSTOM_ID, id,
7017                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
7018                       GDI_X, dx + GDI_ACTIVE_POS(pos->x),
7019                       GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
7020                       GDI_WIDTH, gfx->width,
7021                       GDI_HEIGHT, gfx->height,
7022                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7023                       GDI_STATE, GD_BUTTON_UNPRESSED,
7024                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
7025                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
7026                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7027                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7028                       GDI_DECORATION_SIZE, pos->size, pos->size,
7029                       GDI_DECORATION_SHIFTING, 1, 1,
7030                       GDI_DIRECT_DRAW, FALSE,
7031                       GDI_EVENT_MASK, event_mask,
7032                       GDI_CALLBACK_ACTION, HandleToolButtons,
7033                       GDI_END);
7034
7035     if (gi == NULL)
7036       Error(ERR_EXIT, "cannot create gadget");
7037
7038     tool_gadget[id] = gi;
7039   }
7040 }
7041
7042 #else
7043
7044 /* graphic position values for tool buttons */
7045 #define TOOL_BUTTON_YES_XPOS            2
7046 #define TOOL_BUTTON_YES_YPOS            250
7047 #define TOOL_BUTTON_YES_GFX_YPOS        0
7048 #define TOOL_BUTTON_YES_XSIZE           46
7049 #define TOOL_BUTTON_YES_YSIZE           28
7050 #define TOOL_BUTTON_NO_XPOS             52
7051 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
7052 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
7053 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
7054 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
7055 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
7056 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
7057 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
7058 #define TOOL_BUTTON_CONFIRM_XSIZE       96
7059 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
7060 #define TOOL_BUTTON_PLAYER_XSIZE        30
7061 #define TOOL_BUTTON_PLAYER_YSIZE        30
7062 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
7063 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
7064 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
7065 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
7066 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7067                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7068 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7069                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7070 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7071                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
7072 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
7073                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
7074 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7075                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7076 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7077                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
7078 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7079                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7080 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
7081                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
7082
7083 static struct
7084 {
7085   int xpos, ypos;
7086   int x, y;
7087   int width, height;
7088   int gadget_id;
7089   char *infotext;
7090 } toolbutton_info[NUM_TOOL_BUTTONS] =
7091 {
7092   {
7093     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
7094     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
7095     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
7096     TOOL_CTRL_ID_YES,
7097     "yes"
7098   },
7099   {
7100     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
7101     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
7102     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
7103     TOOL_CTRL_ID_NO,
7104     "no"
7105   },
7106   {
7107     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
7108     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
7109     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
7110     TOOL_CTRL_ID_CONFIRM,
7111     "confirm"
7112   },
7113   {
7114     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7115     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
7116     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7117     TOOL_CTRL_ID_PLAYER_1,
7118     "player 1"
7119   },
7120   {
7121     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7122     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
7123     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7124     TOOL_CTRL_ID_PLAYER_2,
7125     "player 2"
7126   },
7127   {
7128     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7129     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
7130     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7131     TOOL_CTRL_ID_PLAYER_3,
7132     "player 3"
7133   },
7134   {
7135     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
7136     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
7137     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
7138     TOOL_CTRL_ID_PLAYER_4,
7139     "player 4"
7140   }
7141 };
7142
7143 void CreateToolButtons()
7144 {
7145   int i;
7146
7147   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7148   {
7149     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
7150     Bitmap *deco_bitmap = None;
7151     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
7152     struct GadgetInfo *gi;
7153     unsigned int event_mask;
7154     int gd_xoffset, gd_yoffset;
7155     int gd_x1, gd_x2, gd_y;
7156     int id = i;
7157
7158     event_mask = GD_EVENT_RELEASED;
7159
7160     gd_xoffset = toolbutton_info[i].xpos;
7161     gd_yoffset = toolbutton_info[i].ypos;
7162     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
7163     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
7164     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
7165
7166     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
7167     {
7168       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
7169
7170       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
7171                            &deco_bitmap, &deco_x, &deco_y);
7172       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
7173       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
7174     }
7175
7176     gi = CreateGadget(GDI_CUSTOM_ID, id,
7177                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
7178                       GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
7179                       GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
7180                       GDI_WIDTH, toolbutton_info[i].width,
7181                       GDI_HEIGHT, toolbutton_info[i].height,
7182                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
7183                       GDI_STATE, GD_BUTTON_UNPRESSED,
7184                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
7185                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
7186                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
7187                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
7188                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7189                       GDI_DECORATION_SHIFTING, 1, 1,
7190                       GDI_DIRECT_DRAW, FALSE,
7191                       GDI_EVENT_MASK, event_mask,
7192                       GDI_CALLBACK_ACTION, HandleToolButtons,
7193                       GDI_END);
7194
7195     if (gi == NULL)
7196       Error(ERR_EXIT, "cannot create gadget");
7197
7198     tool_gadget[id] = gi;
7199   }
7200 }
7201
7202 #endif
7203
7204 void FreeToolButtons()
7205 {
7206   int i;
7207
7208   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7209     FreeGadget(tool_gadget[i]);
7210 }
7211
7212 static void UnmapToolButtons()
7213 {
7214   int i;
7215
7216   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7217     UnmapGadget(tool_gadget[i]);
7218 }
7219
7220 static void HandleToolButtons(struct GadgetInfo *gi)
7221 {
7222   request_gadget_id = gi->custom_id;
7223 }
7224
7225 static struct Mapping_EM_to_RND_object
7226 {
7227   int element_em;
7228   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
7229   boolean is_backside;                  /* backside of moving element */
7230
7231   int element_rnd;
7232   int action;
7233   int direction;
7234 }
7235 em_object_mapping_list[] =
7236 {
7237   {
7238     Xblank,                             TRUE,   FALSE,
7239     EL_EMPTY,                           -1, -1
7240   },
7241   {
7242     Yacid_splash_eB,                    FALSE,  FALSE,
7243     EL_ACID_SPLASH_RIGHT,               -1, -1
7244   },
7245   {
7246     Yacid_splash_wB,                    FALSE,  FALSE,
7247     EL_ACID_SPLASH_LEFT,                -1, -1
7248   },
7249
7250 #ifdef EM_ENGINE_BAD_ROLL
7251   {
7252     Xstone_force_e,                     FALSE,  FALSE,
7253     EL_ROCK,                            -1, MV_BIT_RIGHT
7254   },
7255   {
7256     Xstone_force_w,                     FALSE,  FALSE,
7257     EL_ROCK,                            -1, MV_BIT_LEFT
7258   },
7259   {
7260     Xnut_force_e,                       FALSE,  FALSE,
7261     EL_NUT,                             -1, MV_BIT_RIGHT
7262   },
7263   {
7264     Xnut_force_w,                       FALSE,  FALSE,
7265     EL_NUT,                             -1, MV_BIT_LEFT
7266   },
7267   {
7268     Xspring_force_e,                    FALSE,  FALSE,
7269     EL_SPRING,                          -1, MV_BIT_RIGHT
7270   },
7271   {
7272     Xspring_force_w,                    FALSE,  FALSE,
7273     EL_SPRING,                          -1, MV_BIT_LEFT
7274   },
7275   {
7276     Xemerald_force_e,                   FALSE,  FALSE,
7277     EL_EMERALD,                         -1, MV_BIT_RIGHT
7278   },
7279   {
7280     Xemerald_force_w,                   FALSE,  FALSE,
7281     EL_EMERALD,                         -1, MV_BIT_LEFT
7282   },
7283   {
7284     Xdiamond_force_e,                   FALSE,  FALSE,
7285     EL_DIAMOND,                         -1, MV_BIT_RIGHT
7286   },
7287   {
7288     Xdiamond_force_w,                   FALSE,  FALSE,
7289     EL_DIAMOND,                         -1, MV_BIT_LEFT
7290   },
7291   {
7292     Xbomb_force_e,                      FALSE,  FALSE,
7293     EL_BOMB,                            -1, MV_BIT_RIGHT
7294   },
7295   {
7296     Xbomb_force_w,                      FALSE,  FALSE,
7297     EL_BOMB,                            -1, MV_BIT_LEFT
7298   },
7299 #endif  /* EM_ENGINE_BAD_ROLL */
7300
7301   {
7302     Xstone,                             TRUE,   FALSE,
7303     EL_ROCK,                            -1, -1
7304   },
7305   {
7306     Xstone_pause,                       FALSE,  FALSE,
7307     EL_ROCK,                            -1, -1
7308   },
7309   {
7310     Xstone_fall,                        FALSE,  FALSE,
7311     EL_ROCK,                            -1, -1
7312   },
7313   {
7314     Ystone_s,                           FALSE,  FALSE,
7315     EL_ROCK,                            ACTION_FALLING, -1
7316   },
7317   {
7318     Ystone_sB,                          FALSE,  TRUE,
7319     EL_ROCK,                            ACTION_FALLING, -1
7320   },
7321   {
7322     Ystone_e,                           FALSE,  FALSE,
7323     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7324   },
7325   {
7326     Ystone_eB,                          FALSE,  TRUE,
7327     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7328   },
7329   {
7330     Ystone_w,                           FALSE,  FALSE,
7331     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7332   },
7333   {
7334     Ystone_wB,                          FALSE,  TRUE,
7335     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7336   },
7337   {
7338     Xnut,                               TRUE,   FALSE,
7339     EL_NUT,                             -1, -1
7340   },
7341   {
7342     Xnut_pause,                         FALSE,  FALSE,
7343     EL_NUT,                             -1, -1
7344   },
7345   {
7346     Xnut_fall,                          FALSE,  FALSE,
7347     EL_NUT,                             -1, -1
7348   },
7349   {
7350     Ynut_s,                             FALSE,  FALSE,
7351     EL_NUT,                             ACTION_FALLING, -1
7352   },
7353   {
7354     Ynut_sB,                            FALSE,  TRUE,
7355     EL_NUT,                             ACTION_FALLING, -1
7356   },
7357   {
7358     Ynut_e,                             FALSE,  FALSE,
7359     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7360   },
7361   {
7362     Ynut_eB,                            FALSE,  TRUE,
7363     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7364   },
7365   {
7366     Ynut_w,                             FALSE,  FALSE,
7367     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7368   },
7369   {
7370     Ynut_wB,                            FALSE,  TRUE,
7371     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7372   },
7373   {
7374     Xbug_n,                             TRUE,   FALSE,
7375     EL_BUG_UP,                          -1, -1
7376   },
7377   {
7378     Xbug_e,                             TRUE,   FALSE,
7379     EL_BUG_RIGHT,                       -1, -1
7380   },
7381   {
7382     Xbug_s,                             TRUE,   FALSE,
7383     EL_BUG_DOWN,                        -1, -1
7384   },
7385   {
7386     Xbug_w,                             TRUE,   FALSE,
7387     EL_BUG_LEFT,                        -1, -1
7388   },
7389   {
7390     Xbug_gon,                           FALSE,  FALSE,
7391     EL_BUG_UP,                          -1, -1
7392   },
7393   {
7394     Xbug_goe,                           FALSE,  FALSE,
7395     EL_BUG_RIGHT,                       -1, -1
7396   },
7397   {
7398     Xbug_gos,                           FALSE,  FALSE,
7399     EL_BUG_DOWN,                        -1, -1
7400   },
7401   {
7402     Xbug_gow,                           FALSE,  FALSE,
7403     EL_BUG_LEFT,                        -1, -1
7404   },
7405   {
7406     Ybug_n,                             FALSE,  FALSE,
7407     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7408   },
7409   {
7410     Ybug_nB,                            FALSE,  TRUE,
7411     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7412   },
7413   {
7414     Ybug_e,                             FALSE,  FALSE,
7415     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7416   },
7417   {
7418     Ybug_eB,                            FALSE,  TRUE,
7419     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7420   },
7421   {
7422     Ybug_s,                             FALSE,  FALSE,
7423     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7424   },
7425   {
7426     Ybug_sB,                            FALSE,  TRUE,
7427     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7428   },
7429   {
7430     Ybug_w,                             FALSE,  FALSE,
7431     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7432   },
7433   {
7434     Ybug_wB,                            FALSE,  TRUE,
7435     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7436   },
7437   {
7438     Ybug_w_n,                           FALSE,  FALSE,
7439     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7440   },
7441   {
7442     Ybug_n_e,                           FALSE,  FALSE,
7443     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7444   },
7445   {
7446     Ybug_e_s,                           FALSE,  FALSE,
7447     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7448   },
7449   {
7450     Ybug_s_w,                           FALSE,  FALSE,
7451     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7452   },
7453   {
7454     Ybug_e_n,                           FALSE,  FALSE,
7455     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7456   },
7457   {
7458     Ybug_s_e,                           FALSE,  FALSE,
7459     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7460   },
7461   {
7462     Ybug_w_s,                           FALSE,  FALSE,
7463     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7464   },
7465   {
7466     Ybug_n_w,                           FALSE,  FALSE,
7467     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7468   },
7469   {
7470     Ybug_stone,                         FALSE,  FALSE,
7471     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
7472   },
7473   {
7474     Ybug_spring,                        FALSE,  FALSE,
7475     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
7476   },
7477   {
7478     Xtank_n,                            TRUE,   FALSE,
7479     EL_SPACESHIP_UP,                    -1, -1
7480   },
7481   {
7482     Xtank_e,                            TRUE,   FALSE,
7483     EL_SPACESHIP_RIGHT,                 -1, -1
7484   },
7485   {
7486     Xtank_s,                            TRUE,   FALSE,
7487     EL_SPACESHIP_DOWN,                  -1, -1
7488   },
7489   {
7490     Xtank_w,                            TRUE,   FALSE,
7491     EL_SPACESHIP_LEFT,                  -1, -1
7492   },
7493   {
7494     Xtank_gon,                          FALSE,  FALSE,
7495     EL_SPACESHIP_UP,                    -1, -1
7496   },
7497   {
7498     Xtank_goe,                          FALSE,  FALSE,
7499     EL_SPACESHIP_RIGHT,                 -1, -1
7500   },
7501   {
7502     Xtank_gos,                          FALSE,  FALSE,
7503     EL_SPACESHIP_DOWN,                  -1, -1
7504   },
7505   {
7506     Xtank_gow,                          FALSE,  FALSE,
7507     EL_SPACESHIP_LEFT,                  -1, -1
7508   },
7509   {
7510     Ytank_n,                            FALSE,  FALSE,
7511     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7512   },
7513   {
7514     Ytank_nB,                           FALSE,  TRUE,
7515     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7516   },
7517   {
7518     Ytank_e,                            FALSE,  FALSE,
7519     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7520   },
7521   {
7522     Ytank_eB,                           FALSE,  TRUE,
7523     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7524   },
7525   {
7526     Ytank_s,                            FALSE,  FALSE,
7527     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7528   },
7529   {
7530     Ytank_sB,                           FALSE,  TRUE,
7531     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7532   },
7533   {
7534     Ytank_w,                            FALSE,  FALSE,
7535     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7536   },
7537   {
7538     Ytank_wB,                           FALSE,  TRUE,
7539     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7540   },
7541   {
7542     Ytank_w_n,                          FALSE,  FALSE,
7543     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7544   },
7545   {
7546     Ytank_n_e,                          FALSE,  FALSE,
7547     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7548   },
7549   {
7550     Ytank_e_s,                          FALSE,  FALSE,
7551     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7552   },
7553   {
7554     Ytank_s_w,                          FALSE,  FALSE,
7555     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7556   },
7557   {
7558     Ytank_e_n,                          FALSE,  FALSE,
7559     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7560   },
7561   {
7562     Ytank_s_e,                          FALSE,  FALSE,
7563     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7564   },
7565   {
7566     Ytank_w_s,                          FALSE,  FALSE,
7567     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7568   },
7569   {
7570     Ytank_n_w,                          FALSE,  FALSE,
7571     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7572   },
7573   {
7574     Ytank_stone,                        FALSE,  FALSE,
7575     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
7576   },
7577   {
7578     Ytank_spring,                       FALSE,  FALSE,
7579     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
7580   },
7581   {
7582     Xandroid,                           TRUE,   FALSE,
7583     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
7584   },
7585   {
7586     Xandroid_1_n,                       FALSE,  FALSE,
7587     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7588   },
7589   {
7590     Xandroid_2_n,                       FALSE,  FALSE,
7591     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7592   },
7593   {
7594     Xandroid_1_e,                       FALSE,  FALSE,
7595     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7596   },
7597   {
7598     Xandroid_2_e,                       FALSE,  FALSE,
7599     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7600   },
7601   {
7602     Xandroid_1_w,                       FALSE,  FALSE,
7603     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7604   },
7605   {
7606     Xandroid_2_w,                       FALSE,  FALSE,
7607     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7608   },
7609   {
7610     Xandroid_1_s,                       FALSE,  FALSE,
7611     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7612   },
7613   {
7614     Xandroid_2_s,                       FALSE,  FALSE,
7615     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7616   },
7617   {
7618     Yandroid_n,                         FALSE,  FALSE,
7619     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7620   },
7621   {
7622     Yandroid_nB,                        FALSE,  TRUE,
7623     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7624   },
7625   {
7626     Yandroid_ne,                        FALSE,  FALSE,
7627     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
7628   },
7629   {
7630     Yandroid_neB,                       FALSE,  TRUE,
7631     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
7632   },
7633   {
7634     Yandroid_e,                         FALSE,  FALSE,
7635     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7636   },
7637   {
7638     Yandroid_eB,                        FALSE,  TRUE,
7639     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7640   },
7641   {
7642     Yandroid_se,                        FALSE,  FALSE,
7643     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
7644   },
7645   {
7646     Yandroid_seB,                       FALSE,  TRUE,
7647     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7648   },
7649   {
7650     Yandroid_s,                         FALSE,  FALSE,
7651     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7652   },
7653   {
7654     Yandroid_sB,                        FALSE,  TRUE,
7655     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7656   },
7657   {
7658     Yandroid_sw,                        FALSE,  FALSE,
7659     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
7660   },
7661   {
7662     Yandroid_swB,                       FALSE,  TRUE,
7663     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
7664   },
7665   {
7666     Yandroid_w,                         FALSE,  FALSE,
7667     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7668   },
7669   {
7670     Yandroid_wB,                        FALSE,  TRUE,
7671     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7672   },
7673   {
7674     Yandroid_nw,                        FALSE,  FALSE,
7675     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
7676   },
7677   {
7678     Yandroid_nwB,                       FALSE,  TRUE,
7679     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
7680   },
7681   {
7682     Xspring,                            TRUE,   FALSE,
7683     EL_SPRING,                          -1, -1
7684   },
7685   {
7686     Xspring_pause,                      FALSE,  FALSE,
7687     EL_SPRING,                          -1, -1
7688   },
7689   {
7690     Xspring_e,                          FALSE,  FALSE,
7691     EL_SPRING,                          -1, -1
7692   },
7693   {
7694     Xspring_w,                          FALSE,  FALSE,
7695     EL_SPRING,                          -1, -1
7696   },
7697   {
7698     Xspring_fall,                       FALSE,  FALSE,
7699     EL_SPRING,                          -1, -1
7700   },
7701   {
7702     Yspring_s,                          FALSE,  FALSE,
7703     EL_SPRING,                          ACTION_FALLING, -1
7704   },
7705   {
7706     Yspring_sB,                         FALSE,  TRUE,
7707     EL_SPRING,                          ACTION_FALLING, -1
7708   },
7709   {
7710     Yspring_e,                          FALSE,  FALSE,
7711     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7712   },
7713   {
7714     Yspring_eB,                         FALSE,  TRUE,
7715     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7716   },
7717   {
7718     Yspring_w,                          FALSE,  FALSE,
7719     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7720   },
7721   {
7722     Yspring_wB,                         FALSE,  TRUE,
7723     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7724   },
7725   {
7726     Yspring_kill_e,                     FALSE,  FALSE,
7727     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7728   },
7729   {
7730     Yspring_kill_eB,                    FALSE,  TRUE,
7731     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7732   },
7733   {
7734     Yspring_kill_w,                     FALSE,  FALSE,
7735     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7736   },
7737   {
7738     Yspring_kill_wB,                    FALSE,  TRUE,
7739     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7740   },
7741   {
7742     Xeater_n,                           TRUE,   FALSE,
7743     EL_YAMYAM_UP,                       -1, -1
7744   },
7745   {
7746     Xeater_e,                           TRUE,   FALSE,
7747     EL_YAMYAM_RIGHT,                    -1, -1
7748   },
7749   {
7750     Xeater_w,                           TRUE,   FALSE,
7751     EL_YAMYAM_LEFT,                     -1, -1
7752   },
7753   {
7754     Xeater_s,                           TRUE,   FALSE,
7755     EL_YAMYAM_DOWN,                     -1, -1
7756   },
7757   {
7758     Yeater_n,                           FALSE,  FALSE,
7759     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7760   },
7761   {
7762     Yeater_nB,                          FALSE,  TRUE,
7763     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7764   },
7765   {
7766     Yeater_e,                           FALSE,  FALSE,
7767     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7768   },
7769   {
7770     Yeater_eB,                          FALSE,  TRUE,
7771     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7772   },
7773   {
7774     Yeater_s,                           FALSE,  FALSE,
7775     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7776   },
7777   {
7778     Yeater_sB,                          FALSE,  TRUE,
7779     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7780   },
7781   {
7782     Yeater_w,                           FALSE,  FALSE,
7783     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7784   },
7785   {
7786     Yeater_wB,                          FALSE,  TRUE,
7787     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7788   },
7789   {
7790     Yeater_stone,                       FALSE,  FALSE,
7791     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
7792   },
7793   {
7794     Yeater_spring,                      FALSE,  FALSE,
7795     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
7796   },
7797   {
7798     Xalien,                             TRUE,   FALSE,
7799     EL_ROBOT,                           -1, -1
7800   },
7801   {
7802     Xalien_pause,                       FALSE,  FALSE,
7803     EL_ROBOT,                           -1, -1
7804   },
7805   {
7806     Yalien_n,                           FALSE,  FALSE,
7807     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7808   },
7809   {
7810     Yalien_nB,                          FALSE,  TRUE,
7811     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7812   },
7813   {
7814     Yalien_e,                           FALSE,  FALSE,
7815     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7816   },
7817   {
7818     Yalien_eB,                          FALSE,  TRUE,
7819     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7820   },
7821   {
7822     Yalien_s,                           FALSE,  FALSE,
7823     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7824   },
7825   {
7826     Yalien_sB,                          FALSE,  TRUE,
7827     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7828   },
7829   {
7830     Yalien_w,                           FALSE,  FALSE,
7831     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7832   },
7833   {
7834     Yalien_wB,                          FALSE,  TRUE,
7835     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7836   },
7837   {
7838     Yalien_stone,                       FALSE,  FALSE,
7839     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
7840   },
7841   {
7842     Yalien_spring,                      FALSE,  FALSE,
7843     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
7844   },
7845   {
7846     Xemerald,                           TRUE,   FALSE,
7847     EL_EMERALD,                         -1, -1
7848   },
7849   {
7850     Xemerald_pause,                     FALSE,  FALSE,
7851     EL_EMERALD,                         -1, -1
7852   },
7853   {
7854     Xemerald_fall,                      FALSE,  FALSE,
7855     EL_EMERALD,                         -1, -1
7856   },
7857   {
7858     Xemerald_shine,                     FALSE,  FALSE,
7859     EL_EMERALD,                         ACTION_TWINKLING, -1
7860   },
7861   {
7862     Yemerald_s,                         FALSE,  FALSE,
7863     EL_EMERALD,                         ACTION_FALLING, -1
7864   },
7865   {
7866     Yemerald_sB,                        FALSE,  TRUE,
7867     EL_EMERALD,                         ACTION_FALLING, -1
7868   },
7869   {
7870     Yemerald_e,                         FALSE,  FALSE,
7871     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7872   },
7873   {
7874     Yemerald_eB,                        FALSE,  TRUE,
7875     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7876   },
7877   {
7878     Yemerald_w,                         FALSE,  FALSE,
7879     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7880   },
7881   {
7882     Yemerald_wB,                        FALSE,  TRUE,
7883     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7884   },
7885   {
7886     Yemerald_eat,                       FALSE,  FALSE,
7887     EL_EMERALD,                         ACTION_COLLECTING, -1
7888   },
7889   {
7890     Yemerald_stone,                     FALSE,  FALSE,
7891     EL_NUT,                             ACTION_BREAKING, -1
7892   },
7893   {
7894     Xdiamond,                           TRUE,   FALSE,
7895     EL_DIAMOND,                         -1, -1
7896   },
7897   {
7898     Xdiamond_pause,                     FALSE,  FALSE,
7899     EL_DIAMOND,                         -1, -1
7900   },
7901   {
7902     Xdiamond_fall,                      FALSE,  FALSE,
7903     EL_DIAMOND,                         -1, -1
7904   },
7905   {
7906     Xdiamond_shine,                     FALSE,  FALSE,
7907     EL_DIAMOND,                         ACTION_TWINKLING, -1
7908   },
7909   {
7910     Ydiamond_s,                         FALSE,  FALSE,
7911     EL_DIAMOND,                         ACTION_FALLING, -1
7912   },
7913   {
7914     Ydiamond_sB,                        FALSE,  TRUE,
7915     EL_DIAMOND,                         ACTION_FALLING, -1
7916   },
7917   {
7918     Ydiamond_e,                         FALSE,  FALSE,
7919     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7920   },
7921   {
7922     Ydiamond_eB,                        FALSE,  TRUE,
7923     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7924   },
7925   {
7926     Ydiamond_w,                         FALSE,  FALSE,
7927     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7928   },
7929   {
7930     Ydiamond_wB,                        FALSE,  TRUE,
7931     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7932   },
7933   {
7934     Ydiamond_eat,                       FALSE,  FALSE,
7935     EL_DIAMOND,                         ACTION_COLLECTING, -1
7936   },
7937   {
7938     Ydiamond_stone,                     FALSE,  FALSE,
7939     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
7940   },
7941   {
7942     Xdrip_fall,                         TRUE,   FALSE,
7943     EL_AMOEBA_DROP,                     -1, -1
7944   },
7945   {
7946     Xdrip_stretch,                      FALSE,  FALSE,
7947     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7948   },
7949   {
7950     Xdrip_stretchB,                     FALSE,  TRUE,
7951     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7952   },
7953   {
7954     Xdrip_eat,                          FALSE,  FALSE,
7955     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
7956   },
7957   {
7958     Ydrip_s1,                           FALSE,  FALSE,
7959     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7960   },
7961   {
7962     Ydrip_s1B,                          FALSE,  TRUE,
7963     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7964   },
7965   {
7966     Ydrip_s2,                           FALSE,  FALSE,
7967     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7968   },
7969   {
7970     Ydrip_s2B,                          FALSE,  TRUE,
7971     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7972   },
7973   {
7974     Xbomb,                              TRUE,   FALSE,
7975     EL_BOMB,                            -1, -1
7976   },
7977   {
7978     Xbomb_pause,                        FALSE,  FALSE,
7979     EL_BOMB,                            -1, -1
7980   },
7981   {
7982     Xbomb_fall,                         FALSE,  FALSE,
7983     EL_BOMB,                            -1, -1
7984   },
7985   {
7986     Ybomb_s,                            FALSE,  FALSE,
7987     EL_BOMB,                            ACTION_FALLING, -1
7988   },
7989   {
7990     Ybomb_sB,                           FALSE,  TRUE,
7991     EL_BOMB,                            ACTION_FALLING, -1
7992   },
7993   {
7994     Ybomb_e,                            FALSE,  FALSE,
7995     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7996   },
7997   {
7998     Ybomb_eB,                           FALSE,  TRUE,
7999     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
8000   },
8001   {
8002     Ybomb_w,                            FALSE,  FALSE,
8003     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
8004   },
8005   {
8006     Ybomb_wB,                           FALSE,  TRUE,
8007     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
8008   },
8009   {
8010     Ybomb_eat,                          FALSE,  FALSE,
8011     EL_BOMB,                            ACTION_ACTIVATING, -1
8012   },
8013   {
8014     Xballoon,                           TRUE,   FALSE,
8015     EL_BALLOON,                         -1, -1
8016   },
8017   {
8018     Yballoon_n,                         FALSE,  FALSE,
8019     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
8020   },
8021   {
8022     Yballoon_nB,                        FALSE,  TRUE,
8023     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
8024   },
8025   {
8026     Yballoon_e,                         FALSE,  FALSE,
8027     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
8028   },
8029   {
8030     Yballoon_eB,                        FALSE,  TRUE,
8031     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
8032   },
8033   {
8034     Yballoon_s,                         FALSE,  FALSE,
8035     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
8036   },
8037   {
8038     Yballoon_sB,                        FALSE,  TRUE,
8039     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
8040   },
8041   {
8042     Yballoon_w,                         FALSE,  FALSE,
8043     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
8044   },
8045   {
8046     Yballoon_wB,                        FALSE,  TRUE,
8047     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
8048   },
8049   {
8050     Xgrass,                             TRUE,   FALSE,
8051     EL_EMC_GRASS,                       -1, -1
8052   },
8053   {
8054     Ygrass_nB,                          FALSE,  FALSE,
8055     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
8056   },
8057   {
8058     Ygrass_eB,                          FALSE,  FALSE,
8059     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
8060   },
8061   {
8062     Ygrass_sB,                          FALSE,  FALSE,
8063     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
8064   },
8065   {
8066     Ygrass_wB,                          FALSE,  FALSE,
8067     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
8068   },
8069   {
8070     Xdirt,                              TRUE,   FALSE,
8071     EL_SAND,                            -1, -1
8072   },
8073   {
8074     Ydirt_nB,                           FALSE,  FALSE,
8075     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
8076   },
8077   {
8078     Ydirt_eB,                           FALSE,  FALSE,
8079     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
8080   },
8081   {
8082     Ydirt_sB,                           FALSE,  FALSE,
8083     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
8084   },
8085   {
8086     Ydirt_wB,                           FALSE,  FALSE,
8087     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
8088   },
8089   {
8090     Xacid_ne,                           TRUE,   FALSE,
8091     EL_ACID_POOL_TOPRIGHT,              -1, -1
8092   },
8093   {
8094     Xacid_se,                           TRUE,   FALSE,
8095     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
8096   },
8097   {
8098     Xacid_s,                            TRUE,   FALSE,
8099     EL_ACID_POOL_BOTTOM,                -1, -1
8100   },
8101   {
8102     Xacid_sw,                           TRUE,   FALSE,
8103     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
8104   },
8105   {
8106     Xacid_nw,                           TRUE,   FALSE,
8107     EL_ACID_POOL_TOPLEFT,               -1, -1
8108   },
8109   {
8110     Xacid_1,                            TRUE,   FALSE,
8111     EL_ACID,                            -1, -1
8112   },
8113   {
8114     Xacid_2,                            FALSE,  FALSE,
8115     EL_ACID,                            -1, -1
8116   },
8117   {
8118     Xacid_3,                            FALSE,  FALSE,
8119     EL_ACID,                            -1, -1
8120   },
8121   {
8122     Xacid_4,                            FALSE,  FALSE,
8123     EL_ACID,                            -1, -1
8124   },
8125   {
8126     Xacid_5,                            FALSE,  FALSE,
8127     EL_ACID,                            -1, -1
8128   },
8129   {
8130     Xacid_6,                            FALSE,  FALSE,
8131     EL_ACID,                            -1, -1
8132   },
8133   {
8134     Xacid_7,                            FALSE,  FALSE,
8135     EL_ACID,                            -1, -1
8136   },
8137   {
8138     Xacid_8,                            FALSE,  FALSE,
8139     EL_ACID,                            -1, -1
8140   },
8141   {
8142     Xball_1,                            TRUE,   FALSE,
8143     EL_EMC_MAGIC_BALL,                  -1, -1
8144   },
8145   {
8146     Xball_1B,                           FALSE,  FALSE,
8147     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8148   },
8149   {
8150     Xball_2,                            FALSE,  FALSE,
8151     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8152   },
8153   {
8154     Xball_2B,                           FALSE,  FALSE,
8155     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
8156   },
8157   {
8158     Yball_eat,                          FALSE,  FALSE,
8159     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
8160   },
8161   {
8162     Ykey_1_eat,                         FALSE,  FALSE,
8163     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
8164   },
8165   {
8166     Ykey_2_eat,                         FALSE,  FALSE,
8167     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
8168   },
8169   {
8170     Ykey_3_eat,                         FALSE,  FALSE,
8171     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
8172   },
8173   {
8174     Ykey_4_eat,                         FALSE,  FALSE,
8175     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
8176   },
8177   {
8178     Ykey_5_eat,                         FALSE,  FALSE,
8179     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
8180   },
8181   {
8182     Ykey_6_eat,                         FALSE,  FALSE,
8183     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
8184   },
8185   {
8186     Ykey_7_eat,                         FALSE,  FALSE,
8187     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
8188   },
8189   {
8190     Ykey_8_eat,                         FALSE,  FALSE,
8191     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
8192   },
8193   {
8194     Ylenses_eat,                        FALSE,  FALSE,
8195     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
8196   },
8197   {
8198     Ymagnify_eat,                       FALSE,  FALSE,
8199     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
8200   },
8201   {
8202     Ygrass_eat,                         FALSE,  FALSE,
8203     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
8204   },
8205   {
8206     Ydirt_eat,                          FALSE,  FALSE,
8207     EL_SAND,                            ACTION_SNAPPING, -1
8208   },
8209   {
8210     Xgrow_ns,                           TRUE,   FALSE,
8211     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
8212   },
8213   {
8214     Ygrow_ns_eat,                       FALSE,  FALSE,
8215     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
8216   },
8217   {
8218     Xgrow_ew,                           TRUE,   FALSE,
8219     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
8220   },
8221   {
8222     Ygrow_ew_eat,                       FALSE,  FALSE,
8223     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
8224   },
8225   {
8226     Xwonderwall,                        TRUE,   FALSE,
8227     EL_MAGIC_WALL,                      -1, -1
8228   },
8229   {
8230     XwonderwallB,                       FALSE,  FALSE,
8231     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
8232   },
8233   {
8234     Xamoeba_1,                          TRUE,   FALSE,
8235     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8236   },
8237   {
8238     Xamoeba_2,                          FALSE,  FALSE,
8239     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8240   },
8241   {
8242     Xamoeba_3,                          FALSE,  FALSE,
8243     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8244   },
8245   {
8246     Xamoeba_4,                          FALSE,  FALSE,
8247     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8248   },
8249   {
8250     Xamoeba_5,                          TRUE,   FALSE,
8251     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8252   },
8253   {
8254     Xamoeba_6,                          FALSE,  FALSE,
8255     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8256   },
8257   {
8258     Xamoeba_7,                          FALSE,  FALSE,
8259     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8260   },
8261   {
8262     Xamoeba_8,                          FALSE,  FALSE,
8263     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8264   },
8265   {
8266     Xdoor_1,                            TRUE,   FALSE,
8267     EL_EM_GATE_1,                       -1, -1
8268   },
8269   {
8270     Xdoor_2,                            TRUE,   FALSE,
8271     EL_EM_GATE_2,                       -1, -1
8272   },
8273   {
8274     Xdoor_3,                            TRUE,   FALSE,
8275     EL_EM_GATE_3,                       -1, -1
8276   },
8277   {
8278     Xdoor_4,                            TRUE,   FALSE,
8279     EL_EM_GATE_4,                       -1, -1
8280   },
8281   {
8282     Xdoor_5,                            TRUE,   FALSE,
8283     EL_EMC_GATE_5,                      -1, -1
8284   },
8285   {
8286     Xdoor_6,                            TRUE,   FALSE,
8287     EL_EMC_GATE_6,                      -1, -1
8288   },
8289   {
8290     Xdoor_7,                            TRUE,   FALSE,
8291     EL_EMC_GATE_7,                      -1, -1
8292   },
8293   {
8294     Xdoor_8,                            TRUE,   FALSE,
8295     EL_EMC_GATE_8,                      -1, -1
8296   },
8297   {
8298     Xkey_1,                             TRUE,   FALSE,
8299     EL_EM_KEY_1,                        -1, -1
8300   },
8301   {
8302     Xkey_2,                             TRUE,   FALSE,
8303     EL_EM_KEY_2,                        -1, -1
8304   },
8305   {
8306     Xkey_3,                             TRUE,   FALSE,
8307     EL_EM_KEY_3,                        -1, -1
8308   },
8309   {
8310     Xkey_4,                             TRUE,   FALSE,
8311     EL_EM_KEY_4,                        -1, -1
8312   },
8313   {
8314     Xkey_5,                             TRUE,   FALSE,
8315     EL_EMC_KEY_5,                       -1, -1
8316   },
8317   {
8318     Xkey_6,                             TRUE,   FALSE,
8319     EL_EMC_KEY_6,                       -1, -1
8320   },
8321   {
8322     Xkey_7,                             TRUE,   FALSE,
8323     EL_EMC_KEY_7,                       -1, -1
8324   },
8325   {
8326     Xkey_8,                             TRUE,   FALSE,
8327     EL_EMC_KEY_8,                       -1, -1
8328   },
8329   {
8330     Xwind_n,                            TRUE,   FALSE,
8331     EL_BALLOON_SWITCH_UP,               -1, -1
8332   },
8333   {
8334     Xwind_e,                            TRUE,   FALSE,
8335     EL_BALLOON_SWITCH_RIGHT,            -1, -1
8336   },
8337   {
8338     Xwind_s,                            TRUE,   FALSE,
8339     EL_BALLOON_SWITCH_DOWN,             -1, -1
8340   },
8341   {
8342     Xwind_w,                            TRUE,   FALSE,
8343     EL_BALLOON_SWITCH_LEFT,             -1, -1
8344   },
8345   {
8346     Xwind_nesw,                         TRUE,   FALSE,
8347     EL_BALLOON_SWITCH_ANY,              -1, -1
8348   },
8349   {
8350     Xwind_stop,                         TRUE,   FALSE,
8351     EL_BALLOON_SWITCH_NONE,             -1, -1
8352   },
8353   {
8354     Xexit,                              TRUE,   FALSE,
8355     EL_EM_EXIT_CLOSED,                  -1, -1
8356   },
8357   {
8358     Xexit_1,                            TRUE,   FALSE,
8359     EL_EM_EXIT_OPEN,                    -1, -1
8360   },
8361   {
8362     Xexit_2,                            FALSE,  FALSE,
8363     EL_EM_EXIT_OPEN,                    -1, -1
8364   },
8365   {
8366     Xexit_3,                            FALSE,  FALSE,
8367     EL_EM_EXIT_OPEN,                    -1, -1
8368   },
8369   {
8370     Xdynamite,                          TRUE,   FALSE,
8371     EL_EM_DYNAMITE,                     -1, -1
8372   },
8373   {
8374     Ydynamite_eat,                      FALSE,  FALSE,
8375     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
8376   },
8377   {
8378     Xdynamite_1,                        TRUE,   FALSE,
8379     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8380   },
8381   {
8382     Xdynamite_2,                        FALSE,  FALSE,
8383     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8384   },
8385   {
8386     Xdynamite_3,                        FALSE,  FALSE,
8387     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8388   },
8389   {
8390     Xdynamite_4,                        FALSE,  FALSE,
8391     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8392   },
8393   {
8394     Xbumper,                            TRUE,   FALSE,
8395     EL_EMC_SPRING_BUMPER,               -1, -1
8396   },
8397   {
8398     XbumperB,                           FALSE,  FALSE,
8399     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
8400   },
8401   {
8402     Xwheel,                             TRUE,   FALSE,
8403     EL_ROBOT_WHEEL,                     -1, -1
8404   },
8405   {
8406     XwheelB,                            FALSE,  FALSE,
8407     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
8408   },
8409   {
8410     Xswitch,                            TRUE,   FALSE,
8411     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
8412   },
8413   {
8414     XswitchB,                           FALSE,  FALSE,
8415     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
8416   },
8417   {
8418     Xsand,                              TRUE,   FALSE,
8419     EL_QUICKSAND_EMPTY,                 -1, -1
8420   },
8421   {
8422     Xsand_stone,                        TRUE,   FALSE,
8423     EL_QUICKSAND_FULL,                  -1, -1
8424   },
8425   {
8426     Xsand_stonein_1,                    FALSE,  TRUE,
8427     EL_ROCK,                            ACTION_FILLING, -1
8428   },
8429   {
8430     Xsand_stonein_2,                    FALSE,  TRUE,
8431     EL_ROCK,                            ACTION_FILLING, -1
8432   },
8433   {
8434     Xsand_stonein_3,                    FALSE,  TRUE,
8435     EL_ROCK,                            ACTION_FILLING, -1
8436   },
8437   {
8438     Xsand_stonein_4,                    FALSE,  TRUE,
8439     EL_ROCK,                            ACTION_FILLING, -1
8440   },
8441 #if 1
8442   {
8443     Xsand_stonesand_1,                  FALSE,  FALSE,
8444     EL_QUICKSAND_EMPTYING,              -1, -1
8445   },
8446   {
8447     Xsand_stonesand_2,                  FALSE,  FALSE,
8448     EL_QUICKSAND_EMPTYING,              -1, -1
8449   },
8450   {
8451     Xsand_stonesand_3,                  FALSE,  FALSE,
8452     EL_QUICKSAND_EMPTYING,              -1, -1
8453   },
8454   {
8455     Xsand_stonesand_4,                  FALSE,  FALSE,
8456     EL_QUICKSAND_EMPTYING,              -1, -1
8457   },
8458   {
8459     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
8460     EL_QUICKSAND_EMPTYING,              -1, -1
8461   },
8462   {
8463     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
8464     EL_QUICKSAND_EMPTYING,              -1, -1
8465   },
8466 #else
8467   {
8468     Xsand_stonesand_1,                  FALSE,  FALSE,
8469     EL_QUICKSAND_FULL,                  -1, -1
8470   },
8471   {
8472     Xsand_stonesand_2,                  FALSE,  FALSE,
8473     EL_QUICKSAND_FULL,                  -1, -1
8474   },
8475   {
8476     Xsand_stonesand_3,                  FALSE,  FALSE,
8477     EL_QUICKSAND_FULL,                  -1, -1
8478   },
8479   {
8480     Xsand_stonesand_4,                  FALSE,  FALSE,
8481     EL_QUICKSAND_FULL,                  -1, -1
8482   },
8483 #endif
8484   {
8485     Xsand_stoneout_1,                   FALSE,  FALSE,
8486     EL_ROCK,                            ACTION_EMPTYING, -1
8487   },
8488   {
8489     Xsand_stoneout_2,                   FALSE,  FALSE,
8490     EL_ROCK,                            ACTION_EMPTYING, -1
8491   },
8492 #if 1
8493   {
8494     Xsand_sandstone_1,                  FALSE,  FALSE,
8495     EL_QUICKSAND_FILLING,               -1, -1
8496   },
8497   {
8498     Xsand_sandstone_2,                  FALSE,  FALSE,
8499     EL_QUICKSAND_FILLING,               -1, -1
8500   },
8501   {
8502     Xsand_sandstone_3,                  FALSE,  FALSE,
8503     EL_QUICKSAND_FILLING,               -1, -1
8504   },
8505   {
8506     Xsand_sandstone_4,                  FALSE,  FALSE,
8507     EL_QUICKSAND_FILLING,               -1, -1
8508   },
8509 #else
8510   {
8511     Xsand_sandstone_1,                  FALSE,  FALSE,
8512     EL_QUICKSAND_FULL,                  -1, -1
8513   },
8514   {
8515     Xsand_sandstone_2,                  FALSE,  FALSE,
8516     EL_QUICKSAND_FULL,                  -1, -1
8517   },
8518   {
8519     Xsand_sandstone_3,                  FALSE,  FALSE,
8520     EL_QUICKSAND_FULL,                  -1, -1
8521   },
8522   {
8523     Xsand_sandstone_4,                  FALSE,  FALSE,
8524     EL_QUICKSAND_FULL,                  -1, -1
8525   },
8526 #endif
8527   {
8528     Xplant,                             TRUE,   FALSE,
8529     EL_EMC_PLANT,                       -1, -1
8530   },
8531   {
8532     Yplant,                             FALSE,  FALSE,
8533     EL_EMC_PLANT,                       -1, -1
8534   },
8535   {
8536     Xlenses,                            TRUE,   FALSE,
8537     EL_EMC_LENSES,                      -1, -1
8538   },
8539   {
8540     Xmagnify,                           TRUE,   FALSE,
8541     EL_EMC_MAGNIFIER,                   -1, -1
8542   },
8543   {
8544     Xdripper,                           TRUE,   FALSE,
8545     EL_EMC_DRIPPER,                     -1, -1
8546   },
8547   {
8548     XdripperB,                          FALSE,  FALSE,
8549     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
8550   },
8551   {
8552     Xfake_blank,                        TRUE,   FALSE,
8553     EL_INVISIBLE_WALL,                  -1, -1
8554   },
8555   {
8556     Xfake_blankB,                       FALSE,  FALSE,
8557     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
8558   },
8559   {
8560     Xfake_grass,                        TRUE,   FALSE,
8561     EL_EMC_FAKE_GRASS,                  -1, -1
8562   },
8563   {
8564     Xfake_grassB,                       FALSE,  FALSE,
8565     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
8566   },
8567   {
8568     Xfake_door_1,                       TRUE,   FALSE,
8569     EL_EM_GATE_1_GRAY,                  -1, -1
8570   },
8571   {
8572     Xfake_door_2,                       TRUE,   FALSE,
8573     EL_EM_GATE_2_GRAY,                  -1, -1
8574   },
8575   {
8576     Xfake_door_3,                       TRUE,   FALSE,
8577     EL_EM_GATE_3_GRAY,                  -1, -1
8578   },
8579   {
8580     Xfake_door_4,                       TRUE,   FALSE,
8581     EL_EM_GATE_4_GRAY,                  -1, -1
8582   },
8583   {
8584     Xfake_door_5,                       TRUE,   FALSE,
8585     EL_EMC_GATE_5_GRAY,                 -1, -1
8586   },
8587   {
8588     Xfake_door_6,                       TRUE,   FALSE,
8589     EL_EMC_GATE_6_GRAY,                 -1, -1
8590   },
8591   {
8592     Xfake_door_7,                       TRUE,   FALSE,
8593     EL_EMC_GATE_7_GRAY,                 -1, -1
8594   },
8595   {
8596     Xfake_door_8,                       TRUE,   FALSE,
8597     EL_EMC_GATE_8_GRAY,                 -1, -1
8598   },
8599   {
8600     Xfake_acid_1,                       TRUE,   FALSE,
8601     EL_EMC_FAKE_ACID,                   -1, -1
8602   },
8603   {
8604     Xfake_acid_2,                       FALSE,  FALSE,
8605     EL_EMC_FAKE_ACID,                   -1, -1
8606   },
8607   {
8608     Xfake_acid_3,                       FALSE,  FALSE,
8609     EL_EMC_FAKE_ACID,                   -1, -1
8610   },
8611   {
8612     Xfake_acid_4,                       FALSE,  FALSE,
8613     EL_EMC_FAKE_ACID,                   -1, -1
8614   },
8615   {
8616     Xfake_acid_5,                       FALSE,  FALSE,
8617     EL_EMC_FAKE_ACID,                   -1, -1
8618   },
8619   {
8620     Xfake_acid_6,                       FALSE,  FALSE,
8621     EL_EMC_FAKE_ACID,                   -1, -1
8622   },
8623   {
8624     Xfake_acid_7,                       FALSE,  FALSE,
8625     EL_EMC_FAKE_ACID,                   -1, -1
8626   },
8627   {
8628     Xfake_acid_8,                       FALSE,  FALSE,
8629     EL_EMC_FAKE_ACID,                   -1, -1
8630   },
8631   {
8632     Xsteel_1,                           TRUE,   FALSE,
8633     EL_STEELWALL,                       -1, -1
8634   },
8635   {
8636     Xsteel_2,                           TRUE,   FALSE,
8637     EL_EMC_STEELWALL_2,                 -1, -1
8638   },
8639   {
8640     Xsteel_3,                           TRUE,   FALSE,
8641     EL_EMC_STEELWALL_3,                 -1, -1
8642   },
8643   {
8644     Xsteel_4,                           TRUE,   FALSE,
8645     EL_EMC_STEELWALL_4,                 -1, -1
8646   },
8647   {
8648     Xwall_1,                            TRUE,   FALSE,
8649     EL_WALL,                            -1, -1
8650   },
8651   {
8652     Xwall_2,                            TRUE,   FALSE,
8653     EL_EMC_WALL_14,                     -1, -1
8654   },
8655   {
8656     Xwall_3,                            TRUE,   FALSE,
8657     EL_EMC_WALL_15,                     -1, -1
8658   },
8659   {
8660     Xwall_4,                            TRUE,   FALSE,
8661     EL_EMC_WALL_16,                     -1, -1
8662   },
8663   {
8664     Xround_wall_1,                      TRUE,   FALSE,
8665     EL_WALL_SLIPPERY,                   -1, -1
8666   },
8667   {
8668     Xround_wall_2,                      TRUE,   FALSE,
8669     EL_EMC_WALL_SLIPPERY_2,             -1, -1
8670   },
8671   {
8672     Xround_wall_3,                      TRUE,   FALSE,
8673     EL_EMC_WALL_SLIPPERY_3,             -1, -1
8674   },
8675   {
8676     Xround_wall_4,                      TRUE,   FALSE,
8677     EL_EMC_WALL_SLIPPERY_4,             -1, -1
8678   },
8679   {
8680     Xdecor_1,                           TRUE,   FALSE,
8681     EL_EMC_WALL_8,                      -1, -1
8682   },
8683   {
8684     Xdecor_2,                           TRUE,   FALSE,
8685     EL_EMC_WALL_6,                      -1, -1
8686   },
8687   {
8688     Xdecor_3,                           TRUE,   FALSE,
8689     EL_EMC_WALL_4,                      -1, -1
8690   },
8691   {
8692     Xdecor_4,                           TRUE,   FALSE,
8693     EL_EMC_WALL_7,                      -1, -1
8694   },
8695   {
8696     Xdecor_5,                           TRUE,   FALSE,
8697     EL_EMC_WALL_5,                      -1, -1
8698   },
8699   {
8700     Xdecor_6,                           TRUE,   FALSE,
8701     EL_EMC_WALL_9,                      -1, -1
8702   },
8703   {
8704     Xdecor_7,                           TRUE,   FALSE,
8705     EL_EMC_WALL_10,                     -1, -1
8706   },
8707   {
8708     Xdecor_8,                           TRUE,   FALSE,
8709     EL_EMC_WALL_1,                      -1, -1
8710   },
8711   {
8712     Xdecor_9,                           TRUE,   FALSE,
8713     EL_EMC_WALL_2,                      -1, -1
8714   },
8715   {
8716     Xdecor_10,                          TRUE,   FALSE,
8717     EL_EMC_WALL_3,                      -1, -1
8718   },
8719   {
8720     Xdecor_11,                          TRUE,   FALSE,
8721     EL_EMC_WALL_11,                     -1, -1
8722   },
8723   {
8724     Xdecor_12,                          TRUE,   FALSE,
8725     EL_EMC_WALL_12,                     -1, -1
8726   },
8727   {
8728     Xalpha_0,                           TRUE,   FALSE,
8729     EL_CHAR('0'),                       -1, -1
8730   },
8731   {
8732     Xalpha_1,                           TRUE,   FALSE,
8733     EL_CHAR('1'),                       -1, -1
8734   },
8735   {
8736     Xalpha_2,                           TRUE,   FALSE,
8737     EL_CHAR('2'),                       -1, -1
8738   },
8739   {
8740     Xalpha_3,                           TRUE,   FALSE,
8741     EL_CHAR('3'),                       -1, -1
8742   },
8743   {
8744     Xalpha_4,                           TRUE,   FALSE,
8745     EL_CHAR('4'),                       -1, -1
8746   },
8747   {
8748     Xalpha_5,                           TRUE,   FALSE,
8749     EL_CHAR('5'),                       -1, -1
8750   },
8751   {
8752     Xalpha_6,                           TRUE,   FALSE,
8753     EL_CHAR('6'),                       -1, -1
8754   },
8755   {
8756     Xalpha_7,                           TRUE,   FALSE,
8757     EL_CHAR('7'),                       -1, -1
8758   },
8759   {
8760     Xalpha_8,                           TRUE,   FALSE,
8761     EL_CHAR('8'),                       -1, -1
8762   },
8763   {
8764     Xalpha_9,                           TRUE,   FALSE,
8765     EL_CHAR('9'),                       -1, -1
8766   },
8767   {
8768     Xalpha_excla,                       TRUE,   FALSE,
8769     EL_CHAR('!'),                       -1, -1
8770   },
8771   {
8772     Xalpha_quote,                       TRUE,   FALSE,
8773     EL_CHAR('"'),                       -1, -1
8774   },
8775   {
8776     Xalpha_comma,                       TRUE,   FALSE,
8777     EL_CHAR(','),                       -1, -1
8778   },
8779   {
8780     Xalpha_minus,                       TRUE,   FALSE,
8781     EL_CHAR('-'),                       -1, -1
8782   },
8783   {
8784     Xalpha_perio,                       TRUE,   FALSE,
8785     EL_CHAR('.'),                       -1, -1
8786   },
8787   {
8788     Xalpha_colon,                       TRUE,   FALSE,
8789     EL_CHAR(':'),                       -1, -1
8790   },
8791   {
8792     Xalpha_quest,                       TRUE,   FALSE,
8793     EL_CHAR('?'),                       -1, -1
8794   },
8795   {
8796     Xalpha_a,                           TRUE,   FALSE,
8797     EL_CHAR('A'),                       -1, -1
8798   },
8799   {
8800     Xalpha_b,                           TRUE,   FALSE,
8801     EL_CHAR('B'),                       -1, -1
8802   },
8803   {
8804     Xalpha_c,                           TRUE,   FALSE,
8805     EL_CHAR('C'),                       -1, -1
8806   },
8807   {
8808     Xalpha_d,                           TRUE,   FALSE,
8809     EL_CHAR('D'),                       -1, -1
8810   },
8811   {
8812     Xalpha_e,                           TRUE,   FALSE,
8813     EL_CHAR('E'),                       -1, -1
8814   },
8815   {
8816     Xalpha_f,                           TRUE,   FALSE,
8817     EL_CHAR('F'),                       -1, -1
8818   },
8819   {
8820     Xalpha_g,                           TRUE,   FALSE,
8821     EL_CHAR('G'),                       -1, -1
8822   },
8823   {
8824     Xalpha_h,                           TRUE,   FALSE,
8825     EL_CHAR('H'),                       -1, -1
8826   },
8827   {
8828     Xalpha_i,                           TRUE,   FALSE,
8829     EL_CHAR('I'),                       -1, -1
8830   },
8831   {
8832     Xalpha_j,                           TRUE,   FALSE,
8833     EL_CHAR('J'),                       -1, -1
8834   },
8835   {
8836     Xalpha_k,                           TRUE,   FALSE,
8837     EL_CHAR('K'),                       -1, -1
8838   },
8839   {
8840     Xalpha_l,                           TRUE,   FALSE,
8841     EL_CHAR('L'),                       -1, -1
8842   },
8843   {
8844     Xalpha_m,                           TRUE,   FALSE,
8845     EL_CHAR('M'),                       -1, -1
8846   },
8847   {
8848     Xalpha_n,                           TRUE,   FALSE,
8849     EL_CHAR('N'),                       -1, -1
8850   },
8851   {
8852     Xalpha_o,                           TRUE,   FALSE,
8853     EL_CHAR('O'),                       -1, -1
8854   },
8855   {
8856     Xalpha_p,                           TRUE,   FALSE,
8857     EL_CHAR('P'),                       -1, -1
8858   },
8859   {
8860     Xalpha_q,                           TRUE,   FALSE,
8861     EL_CHAR('Q'),                       -1, -1
8862   },
8863   {
8864     Xalpha_r,                           TRUE,   FALSE,
8865     EL_CHAR('R'),                       -1, -1
8866   },
8867   {
8868     Xalpha_s,                           TRUE,   FALSE,
8869     EL_CHAR('S'),                       -1, -1
8870   },
8871   {
8872     Xalpha_t,                           TRUE,   FALSE,
8873     EL_CHAR('T'),                       -1, -1
8874   },
8875   {
8876     Xalpha_u,                           TRUE,   FALSE,
8877     EL_CHAR('U'),                       -1, -1
8878   },
8879   {
8880     Xalpha_v,                           TRUE,   FALSE,
8881     EL_CHAR('V'),                       -1, -1
8882   },
8883   {
8884     Xalpha_w,                           TRUE,   FALSE,
8885     EL_CHAR('W'),                       -1, -1
8886   },
8887   {
8888     Xalpha_x,                           TRUE,   FALSE,
8889     EL_CHAR('X'),                       -1, -1
8890   },
8891   {
8892     Xalpha_y,                           TRUE,   FALSE,
8893     EL_CHAR('Y'),                       -1, -1
8894   },
8895   {
8896     Xalpha_z,                           TRUE,   FALSE,
8897     EL_CHAR('Z'),                       -1, -1
8898   },
8899   {
8900     Xalpha_arrow_e,                     TRUE,   FALSE,
8901     EL_CHAR('>'),                       -1, -1
8902   },
8903   {
8904     Xalpha_arrow_w,                     TRUE,   FALSE,
8905     EL_CHAR('<'),                       -1, -1
8906   },
8907   {
8908     Xalpha_copyr,                       TRUE,   FALSE,
8909     EL_CHAR('©'),                       -1, -1
8910   },
8911
8912   {
8913     Xboom_bug,                          FALSE,  FALSE,
8914     EL_BUG,                             ACTION_EXPLODING, -1
8915   },
8916   {
8917     Xboom_bomb,                         FALSE,  FALSE,
8918     EL_BOMB,                            ACTION_EXPLODING, -1
8919   },
8920   {
8921     Xboom_android,                      FALSE,  FALSE,
8922     EL_EMC_ANDROID,                     ACTION_OTHER, -1
8923   },
8924   {
8925     Xboom_1,                            FALSE,  FALSE,
8926     EL_DEFAULT,                         ACTION_EXPLODING, -1
8927   },
8928   {
8929     Xboom_2,                            FALSE,  FALSE,
8930     EL_DEFAULT,                         ACTION_EXPLODING, -1
8931   },
8932   {
8933     Znormal,                            FALSE,  FALSE,
8934     EL_EMPTY,                           -1, -1
8935   },
8936   {
8937     Zdynamite,                          FALSE,  FALSE,
8938     EL_EMPTY,                           -1, -1
8939   },
8940   {
8941     Zplayer,                            FALSE,  FALSE,
8942     EL_EMPTY,                           -1, -1
8943   },
8944   {
8945     ZBORDER,                            FALSE,  FALSE,
8946     EL_EMPTY,                           -1, -1
8947   },
8948
8949   {
8950     -1,                                 FALSE,  FALSE,
8951     -1,                                 -1, -1
8952   }
8953 };
8954
8955 static struct Mapping_EM_to_RND_player
8956 {
8957   int action_em;
8958   int player_nr;
8959
8960   int element_rnd;
8961   int action;
8962   int direction;
8963 }
8964 em_player_mapping_list[] =
8965 {
8966   {
8967     SPR_walk + 0,                       0,
8968     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
8969   },
8970   {
8971     SPR_walk + 1,                       0,
8972     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
8973   },
8974   {
8975     SPR_walk + 2,                       0,
8976     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
8977   },
8978   {
8979     SPR_walk + 3,                       0,
8980     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
8981   },
8982   {
8983     SPR_push + 0,                       0,
8984     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
8985   },
8986   {
8987     SPR_push + 1,                       0,
8988     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
8989   },
8990   {
8991     SPR_push + 2,                       0,
8992     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
8993   },
8994   {
8995     SPR_push + 3,                       0,
8996     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
8997   },
8998   {
8999     SPR_spray + 0,                      0,
9000     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
9001   },
9002   {
9003     SPR_spray + 1,                      0,
9004     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9005   },
9006   {
9007     SPR_spray + 2,                      0,
9008     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
9009   },
9010   {
9011     SPR_spray + 3,                      0,
9012     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
9013   },
9014   {
9015     SPR_walk + 0,                       1,
9016     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
9017   },
9018   {
9019     SPR_walk + 1,                       1,
9020     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
9021   },
9022   {
9023     SPR_walk + 2,                       1,
9024     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
9025   },
9026   {
9027     SPR_walk + 3,                       1,
9028     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
9029   },
9030   {
9031     SPR_push + 0,                       1,
9032     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
9033   },
9034   {
9035     SPR_push + 1,                       1,
9036     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
9037   },
9038   {
9039     SPR_push + 2,                       1,
9040     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
9041   },
9042   {
9043     SPR_push + 3,                       1,
9044     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
9045   },
9046   {
9047     SPR_spray + 0,                      1,
9048     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
9049   },
9050   {
9051     SPR_spray + 1,                      1,
9052     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9053   },
9054   {
9055     SPR_spray + 2,                      1,
9056     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
9057   },
9058   {
9059     SPR_spray + 3,                      1,
9060     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
9061   },
9062   {
9063     SPR_still,                          0,
9064     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
9065   },
9066   {
9067     SPR_still,                          1,
9068     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
9069   },
9070   {
9071     SPR_walk + 0,                       2,
9072     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
9073   },
9074   {
9075     SPR_walk + 1,                       2,
9076     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
9077   },
9078   {
9079     SPR_walk + 2,                       2,
9080     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
9081   },
9082   {
9083     SPR_walk + 3,                       2,
9084     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
9085   },
9086   {
9087     SPR_push + 0,                       2,
9088     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
9089   },
9090   {
9091     SPR_push + 1,                       2,
9092     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
9093   },
9094   {
9095     SPR_push + 2,                       2,
9096     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
9097   },
9098   {
9099     SPR_push + 3,                       2,
9100     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
9101   },
9102   {
9103     SPR_spray + 0,                      2,
9104     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
9105   },
9106   {
9107     SPR_spray + 1,                      2,
9108     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9109   },
9110   {
9111     SPR_spray + 2,                      2,
9112     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
9113   },
9114   {
9115     SPR_spray + 3,                      2,
9116     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
9117   },
9118   {
9119     SPR_walk + 0,                       3,
9120     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
9121   },
9122   {
9123     SPR_walk + 1,                       3,
9124     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
9125   },
9126   {
9127     SPR_walk + 2,                       3,
9128     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
9129   },
9130   {
9131     SPR_walk + 3,                       3,
9132     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
9133   },
9134   {
9135     SPR_push + 0,                       3,
9136     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
9137   },
9138   {
9139     SPR_push + 1,                       3,
9140     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
9141   },
9142   {
9143     SPR_push + 2,                       3,
9144     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
9145   },
9146   {
9147     SPR_push + 3,                       3,
9148     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
9149   },
9150   {
9151     SPR_spray + 0,                      3,
9152     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
9153   },
9154   {
9155     SPR_spray + 1,                      3,
9156     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
9157   },
9158   {
9159     SPR_spray + 2,                      3,
9160     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
9161   },
9162   {
9163     SPR_spray + 3,                      3,
9164     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
9165   },
9166   {
9167     SPR_still,                          2,
9168     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
9169   },
9170   {
9171     SPR_still,                          3,
9172     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
9173   },
9174
9175   {
9176     -1,                                 -1,
9177     -1,                                 -1, -1
9178   }
9179 };
9180
9181 int map_element_RND_to_EM(int element_rnd)
9182 {
9183   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
9184   static boolean mapping_initialized = FALSE;
9185
9186   if (!mapping_initialized)
9187   {
9188     int i;
9189
9190     /* return "Xalpha_quest" for all undefined elements in mapping array */
9191     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9192       mapping_RND_to_EM[i] = Xalpha_quest;
9193
9194     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9195       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9196         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9197           em_object_mapping_list[i].element_em;
9198
9199     mapping_initialized = TRUE;
9200   }
9201
9202   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9203     return mapping_RND_to_EM[element_rnd];
9204
9205   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9206
9207   return EL_UNKNOWN;
9208 }
9209
9210 int map_element_EM_to_RND(int element_em)
9211 {
9212   static unsigned short mapping_EM_to_RND[TILE_MAX];
9213   static boolean mapping_initialized = FALSE;
9214
9215   if (!mapping_initialized)
9216   {
9217     int i;
9218
9219     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9220     for (i = 0; i < TILE_MAX; i++)
9221       mapping_EM_to_RND[i] = EL_UNKNOWN;
9222
9223     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9224       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9225         em_object_mapping_list[i].element_rnd;
9226
9227     mapping_initialized = TRUE;
9228   }
9229
9230   if (element_em >= 0 && element_em < TILE_MAX)
9231     return mapping_EM_to_RND[element_em];
9232
9233   Error(ERR_WARN, "invalid EM level element %d", element_em);
9234
9235   return EL_UNKNOWN;
9236 }
9237
9238 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9239 {
9240   struct LevelInfo_EM *level_em = level->native_em_level;
9241   struct LEVEL *lev = level_em->lev;
9242   int i, j;
9243
9244   for (i = 0; i < TILE_MAX; i++)
9245     lev->android_array[i] = Xblank;
9246
9247   for (i = 0; i < level->num_android_clone_elements; i++)
9248   {
9249     int element_rnd = level->android_clone_element[i];
9250     int element_em = map_element_RND_to_EM(element_rnd);
9251
9252     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9253       if (em_object_mapping_list[j].element_rnd == element_rnd)
9254         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9255   }
9256 }
9257
9258 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9259 {
9260   struct LevelInfo_EM *level_em = level->native_em_level;
9261   struct LEVEL *lev = level_em->lev;
9262   int i, j;
9263
9264   level->num_android_clone_elements = 0;
9265
9266   for (i = 0; i < TILE_MAX; i++)
9267   {
9268     int element_em = lev->android_array[i];
9269     int element_rnd;
9270     boolean element_found = FALSE;
9271
9272     if (element_em == Xblank)
9273       continue;
9274
9275     element_rnd = map_element_EM_to_RND(element_em);
9276
9277     for (j = 0; j < level->num_android_clone_elements; j++)
9278       if (level->android_clone_element[j] == element_rnd)
9279         element_found = TRUE;
9280
9281     if (!element_found)
9282     {
9283       level->android_clone_element[level->num_android_clone_elements++] =
9284         element_rnd;
9285
9286       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9287         break;
9288     }
9289   }
9290
9291   if (level->num_android_clone_elements == 0)
9292   {
9293     level->num_android_clone_elements = 1;
9294     level->android_clone_element[0] = EL_EMPTY;
9295   }
9296 }
9297
9298 int map_direction_RND_to_EM(int direction)
9299 {
9300   return (direction == MV_UP    ? 0 :
9301           direction == MV_RIGHT ? 1 :
9302           direction == MV_DOWN  ? 2 :
9303           direction == MV_LEFT  ? 3 :
9304           -1);
9305 }
9306
9307 int map_direction_EM_to_RND(int direction)
9308 {
9309   return (direction == 0 ? MV_UP    :
9310           direction == 1 ? MV_RIGHT :
9311           direction == 2 ? MV_DOWN  :
9312           direction == 3 ? MV_LEFT  :
9313           MV_NONE);
9314 }
9315
9316 int map_element_RND_to_SP(int element_rnd)
9317 {
9318   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
9319
9320   if (element_rnd >= EL_SP_START &&
9321       element_rnd <= EL_SP_END)
9322     element_sp = element_rnd - EL_SP_START;
9323   else if (element_rnd == EL_EMPTY_SPACE)
9324     element_sp = 0x00;
9325   else if (element_rnd == EL_INVISIBLE_WALL)
9326     element_sp = 0x28;
9327
9328   return element_sp;
9329 }
9330
9331 int map_element_SP_to_RND(int element_sp)
9332 {
9333   int element_rnd = EL_UNKNOWN;
9334
9335   if (element_sp >= 0x00 &&
9336       element_sp <= 0x27)
9337     element_rnd = EL_SP_START + element_sp;
9338   else if (element_sp == 0x28)
9339     element_rnd = EL_INVISIBLE_WALL;
9340
9341   return element_rnd;
9342 }
9343
9344 int map_action_SP_to_RND(int action_sp)
9345 {
9346   switch (action_sp)
9347   {
9348     case actActive:             return ACTION_ACTIVE;
9349     case actImpact:             return ACTION_IMPACT;
9350     case actExploding:          return ACTION_EXPLODING;
9351     case actDigging:            return ACTION_DIGGING;
9352     case actSnapping:           return ACTION_SNAPPING;
9353     case actCollecting:         return ACTION_COLLECTING;
9354     case actPassing:            return ACTION_PASSING;
9355     case actPushing:            return ACTION_PUSHING;
9356     case actDropping:           return ACTION_DROPPING;
9357
9358     default:                    return ACTION_DEFAULT;
9359   }
9360 }
9361
9362 int get_next_element(int element)
9363 {
9364   switch (element)
9365   {
9366     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
9367     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
9368     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
9369     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
9370     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
9371     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
9372     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
9373     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
9374     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
9375     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
9376     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
9377
9378     default:                            return element;
9379   }
9380 }
9381
9382 #if 0
9383 int el_act_dir2img(int element, int action, int direction)
9384 {
9385   element = GFX_ELEMENT(element);
9386
9387   if (direction == MV_NONE)
9388     return element_info[element].graphic[action];
9389
9390   direction = MV_DIR_TO_BIT(direction);
9391
9392   return element_info[element].direction_graphic[action][direction];
9393 }
9394 #else
9395 int el_act_dir2img(int element, int action, int direction)
9396 {
9397   element = GFX_ELEMENT(element);
9398   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9399
9400   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9401   return element_info[element].direction_graphic[action][direction];
9402 }
9403 #endif
9404
9405 #if 0
9406 static int el_act_dir2crm(int element, int action, int direction)
9407 {
9408   element = GFX_ELEMENT(element);
9409
9410   if (direction == MV_NONE)
9411     return element_info[element].crumbled[action];
9412
9413   direction = MV_DIR_TO_BIT(direction);
9414
9415   return element_info[element].direction_crumbled[action][direction];
9416 }
9417 #else
9418 static int el_act_dir2crm(int element, int action, int direction)
9419 {
9420   element = GFX_ELEMENT(element);
9421   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9422
9423   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9424   return element_info[element].direction_crumbled[action][direction];
9425 }
9426 #endif
9427
9428 int el_act2img(int element, int action)
9429 {
9430   element = GFX_ELEMENT(element);
9431
9432   return element_info[element].graphic[action];
9433 }
9434
9435 int el_act2crm(int element, int action)
9436 {
9437   element = GFX_ELEMENT(element);
9438
9439   return element_info[element].crumbled[action];
9440 }
9441
9442 int el_dir2img(int element, int direction)
9443 {
9444   element = GFX_ELEMENT(element);
9445
9446   return el_act_dir2img(element, ACTION_DEFAULT, direction);
9447 }
9448
9449 int el2baseimg(int element)
9450 {
9451   return element_info[element].graphic[ACTION_DEFAULT];
9452 }
9453
9454 int el2img(int element)
9455 {
9456   element = GFX_ELEMENT(element);
9457
9458   return element_info[element].graphic[ACTION_DEFAULT];
9459 }
9460
9461 int el2edimg(int element)
9462 {
9463   element = GFX_ELEMENT(element);
9464
9465   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9466 }
9467
9468 int el2preimg(int element)
9469 {
9470   element = GFX_ELEMENT(element);
9471
9472   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9473 }
9474
9475 int el2panelimg(int element)
9476 {
9477   element = GFX_ELEMENT(element);
9478
9479   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9480 }
9481
9482 int font2baseimg(int font_nr)
9483 {
9484   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9485 }
9486
9487 int getBeltNrFromBeltElement(int element)
9488 {
9489   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9490           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9491           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9492 }
9493
9494 int getBeltNrFromBeltActiveElement(int element)
9495 {
9496   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9497           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9498           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9499 }
9500
9501 int getBeltNrFromBeltSwitchElement(int element)
9502 {
9503   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9504           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9505           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9506 }
9507
9508 int getBeltDirNrFromBeltElement(int element)
9509 {
9510   static int belt_base_element[4] =
9511   {
9512     EL_CONVEYOR_BELT_1_LEFT,
9513     EL_CONVEYOR_BELT_2_LEFT,
9514     EL_CONVEYOR_BELT_3_LEFT,
9515     EL_CONVEYOR_BELT_4_LEFT
9516   };
9517
9518   int belt_nr = getBeltNrFromBeltElement(element);
9519   int belt_dir_nr = element - belt_base_element[belt_nr];
9520
9521   return (belt_dir_nr % 3);
9522 }
9523
9524 int getBeltDirNrFromBeltSwitchElement(int element)
9525 {
9526   static int belt_base_element[4] =
9527   {
9528     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9529     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9530     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9531     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9532   };
9533
9534   int belt_nr = getBeltNrFromBeltSwitchElement(element);
9535   int belt_dir_nr = element - belt_base_element[belt_nr];
9536
9537   return (belt_dir_nr % 3);
9538 }
9539
9540 int getBeltDirFromBeltElement(int element)
9541 {
9542   static int belt_move_dir[3] =
9543   {
9544     MV_LEFT,
9545     MV_NONE,
9546     MV_RIGHT
9547   };
9548
9549   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9550
9551   return belt_move_dir[belt_dir_nr];
9552 }
9553
9554 int getBeltDirFromBeltSwitchElement(int element)
9555 {
9556   static int belt_move_dir[3] =
9557   {
9558     MV_LEFT,
9559     MV_NONE,
9560     MV_RIGHT
9561   };
9562
9563   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9564
9565   return belt_move_dir[belt_dir_nr];
9566 }
9567
9568 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9569 {
9570   static int belt_base_element[4] =
9571   {
9572     EL_CONVEYOR_BELT_1_LEFT,
9573     EL_CONVEYOR_BELT_2_LEFT,
9574     EL_CONVEYOR_BELT_3_LEFT,
9575     EL_CONVEYOR_BELT_4_LEFT
9576   };
9577
9578   return belt_base_element[belt_nr] + belt_dir_nr;
9579 }
9580
9581 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9582 {
9583   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9584
9585   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9586 }
9587
9588 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9589 {
9590   static int belt_base_element[4] =
9591   {
9592     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9593     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9594     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9595     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9596   };
9597
9598   return belt_base_element[belt_nr] + belt_dir_nr;
9599 }
9600
9601 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9602 {
9603   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9604
9605   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9606 }
9607
9608 #if 1
9609 boolean getTeamMode_EM()
9610 {
9611   return game.team_mode;
9612 }
9613 #else
9614 int getNumActivePlayers_EM()
9615 {
9616 #if 1
9617   int num_players = 0;
9618   int i;
9619
9620   if (!tape.playing)
9621     return (setup.team_mode ? MAX_PLAYERS : 1);
9622
9623   for (i = 0; i < MAX_PLAYERS; i++)
9624     if (tape.player_participates[i])
9625       num_players++;
9626
9627   return (num_players > 1 ? MAX_PLAYERS : 1);
9628
9629 #else
9630
9631   int num_players = 0;
9632   int i;
9633
9634   /* when recording game, activate all connected players */
9635   if (!tape.playing)
9636     return -1;
9637
9638   for (i = 0; i < MAX_PLAYERS; i++)
9639     if (tape.player_participates[i])
9640       num_players++;
9641
9642   return num_players;
9643 #endif
9644 }
9645 #endif
9646
9647 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9648 {
9649   int game_frame_delay_value;
9650
9651   game_frame_delay_value =
9652     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9653      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9654      GameFrameDelay);
9655
9656   if (tape.playing && tape.warp_forward && !tape.pausing)
9657     game_frame_delay_value = 0;
9658
9659   return game_frame_delay_value;
9660 }
9661
9662 unsigned int InitRND(int seed)
9663 {
9664   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9665     return InitEngineRandom_EM(seed);
9666   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9667     return InitEngineRandom_SP(seed);
9668   else
9669     return InitEngineRandom_RND(seed);
9670 }
9671
9672 #if 1
9673 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9674 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9675 #endif
9676
9677 inline static int get_effective_element_EM(int tile, int frame_em)
9678 {
9679   int element             = object_mapping[tile].element_rnd;
9680   int action              = object_mapping[tile].action;
9681   boolean is_backside     = object_mapping[tile].is_backside;
9682   boolean action_removing = (action == ACTION_DIGGING ||
9683                              action == ACTION_SNAPPING ||
9684                              action == ACTION_COLLECTING);
9685
9686   if (frame_em < 7)
9687   {
9688     switch (tile)
9689     {
9690       case Yacid_splash_eB:
9691       case Yacid_splash_wB:
9692         return (frame_em > 5 ? EL_EMPTY : element);
9693
9694 #if 0
9695         /* !!! FIX !!! */
9696       case Ydiamond_stone:
9697         //  if (!game.use_native_emc_graphics_engine)
9698         return EL_ROCK;
9699 #endif
9700
9701       default:
9702         return element;
9703     }
9704   }
9705   else  /* frame_em == 7 */
9706   {
9707     switch (tile)
9708     {
9709       case Yacid_splash_eB:
9710       case Yacid_splash_wB:
9711         return EL_EMPTY;
9712
9713       case Yemerald_stone:
9714         return EL_EMERALD;
9715
9716       case Ydiamond_stone:
9717         return EL_ROCK;
9718
9719       case Xdrip_stretch:
9720       case Xdrip_stretchB:
9721       case Ydrip_s1:
9722       case Ydrip_s1B:
9723       case Xball_1B:
9724       case Xball_2:
9725       case Xball_2B:
9726       case Yball_eat:
9727       case Ykey_1_eat:
9728       case Ykey_2_eat:
9729       case Ykey_3_eat:
9730       case Ykey_4_eat:
9731       case Ykey_5_eat:
9732       case Ykey_6_eat:
9733       case Ykey_7_eat:
9734       case Ykey_8_eat:
9735       case Ylenses_eat:
9736       case Ymagnify_eat:
9737       case Ygrass_eat:
9738       case Ydirt_eat:
9739       case Xsand_stonein_1:
9740       case Xsand_stonein_2:
9741       case Xsand_stonein_3:
9742       case Xsand_stonein_4:
9743         return element;
9744
9745       default:
9746         return (is_backside || action_removing ? EL_EMPTY : element);
9747     }
9748   }
9749 }
9750
9751 inline static boolean check_linear_animation_EM(int tile)
9752 {
9753   switch (tile)
9754   {
9755     case Xsand_stonesand_1:
9756     case Xsand_stonesand_quickout_1:
9757     case Xsand_sandstone_1:
9758     case Xsand_stonein_1:
9759     case Xsand_stoneout_1:
9760     case Xboom_1:
9761     case Xdynamite_1:
9762     case Ybug_w_n:
9763     case Ybug_n_e:
9764     case Ybug_e_s:
9765     case Ybug_s_w:
9766     case Ybug_e_n:
9767     case Ybug_s_e:
9768     case Ybug_w_s:
9769     case Ybug_n_w:
9770     case Ytank_w_n:
9771     case Ytank_n_e:
9772     case Ytank_e_s:
9773     case Ytank_s_w:
9774     case Ytank_e_n:
9775     case Ytank_s_e:
9776     case Ytank_w_s:
9777     case Ytank_n_w:
9778 #if 1
9779     case Yacid_splash_eB:
9780     case Yacid_splash_wB:
9781     case Yemerald_stone:
9782 #endif
9783       return TRUE;
9784   }
9785
9786   return FALSE;
9787 }
9788
9789 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9790                                             boolean has_crumbled_graphics,
9791                                             int crumbled, int sync_frame)
9792 {
9793   /* if element can be crumbled, but certain action graphics are just empty
9794      space (like instantly snapping sand to empty space in 1 frame), do not
9795      treat these empty space graphics as crumbled graphics in EMC engine */
9796   if (crumbled == IMG_EMPTY_SPACE)
9797     has_crumbled_graphics = FALSE;
9798
9799   if (has_crumbled_graphics)
9800   {
9801     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9802     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9803                                            g_crumbled->anim_delay,
9804                                            g_crumbled->anim_mode,
9805                                            g_crumbled->anim_start_frame,
9806                                            sync_frame);
9807
9808     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9809                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9810
9811     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9812
9813     g_em->has_crumbled_graphics = TRUE;
9814   }
9815   else
9816   {
9817     g_em->crumbled_bitmap = NULL;
9818     g_em->crumbled_src_x = 0;
9819     g_em->crumbled_src_y = 0;
9820     g_em->crumbled_border_size = 0;
9821
9822     g_em->has_crumbled_graphics = FALSE;
9823   }
9824 }
9825
9826 void ResetGfxAnimation_EM(int x, int y, int tile)
9827 {
9828   GfxFrame[x][y] = 0;
9829 }
9830
9831 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9832                         int tile, int frame_em, int x, int y)
9833 {
9834   int action = object_mapping[tile].action;
9835 #if 1
9836   int direction = object_mapping[tile].direction;
9837   int effective_element = get_effective_element_EM(tile, frame_em);
9838   int graphic = (direction == MV_NONE ?
9839                  el_act2img(effective_element, action) :
9840                  el_act_dir2img(effective_element, action, direction));
9841   struct GraphicInfo *g = &graphic_info[graphic];
9842   int sync_frame;
9843 #endif
9844   boolean action_removing = (action == ACTION_DIGGING ||
9845                              action == ACTION_SNAPPING ||
9846                              action == ACTION_COLLECTING);
9847   boolean action_moving   = (action == ACTION_FALLING ||
9848                              action == ACTION_MOVING ||
9849                              action == ACTION_PUSHING ||
9850                              action == ACTION_EATING ||
9851                              action == ACTION_FILLING ||
9852                              action == ACTION_EMPTYING);
9853   boolean action_falling  = (action == ACTION_FALLING ||
9854                              action == ACTION_FILLING ||
9855                              action == ACTION_EMPTYING);
9856
9857   /* special case: graphic uses "2nd movement tile" and has defined
9858      7 frames for movement animation (or less) => use default graphic
9859      for last (8th) frame which ends the movement animation */
9860   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9861   {
9862     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
9863     graphic = (direction == MV_NONE ?
9864                el_act2img(effective_element, action) :
9865                el_act_dir2img(effective_element, action, direction));
9866
9867     g = &graphic_info[graphic];
9868   }
9869
9870 #if 0
9871   if (tile == Xsand_stonesand_1 ||
9872       tile == Xsand_stonesand_2 ||
9873       tile == Xsand_stonesand_3 ||
9874       tile == Xsand_stonesand_4)
9875     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9876 #endif
9877
9878 #if 1
9879   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9880   {
9881     GfxFrame[x][y] = 0;
9882
9883     // printf("::: resetting... [%d]\n", tile);
9884   }
9885 #else
9886   if (action_removing || check_linear_animation_EM(tile))
9887   {
9888     GfxFrame[x][y] = frame_em;
9889
9890     // printf("::: resetting... [%d]\n", tile);
9891   }
9892 #endif
9893   else if (action_moving)
9894   {
9895     boolean is_backside = object_mapping[tile].is_backside;
9896
9897     if (is_backside)
9898     {
9899       int direction = object_mapping[tile].direction;
9900       int move_dir = (action_falling ? MV_DOWN : direction);
9901
9902       GfxFrame[x][y]++;
9903
9904 #if 1
9905       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9906       if (g->double_movement && frame_em == 0)
9907       {
9908         GfxFrame[x][y] = 0;
9909
9910         // printf("::: resetting... [%d]\n", tile);
9911       }
9912 #endif
9913
9914       if (move_dir == MV_LEFT)
9915         GfxFrame[x - 1][y] = GfxFrame[x][y];
9916       else if (move_dir == MV_RIGHT)
9917         GfxFrame[x + 1][y] = GfxFrame[x][y];
9918       else if (move_dir == MV_UP)
9919         GfxFrame[x][y - 1] = GfxFrame[x][y];
9920       else if (move_dir == MV_DOWN)
9921         GfxFrame[x][y + 1] = GfxFrame[x][y];
9922     }
9923   }
9924   else
9925   {
9926     GfxFrame[x][y]++;
9927
9928     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9929     if (tile == Xsand_stonesand_quickout_1 ||
9930         tile == Xsand_stonesand_quickout_2)
9931       GfxFrame[x][y]++;
9932   }
9933
9934 #if 0
9935   if (tile == Xsand_stonesand_1 ||
9936       tile == Xsand_stonesand_2 ||
9937       tile == Xsand_stonesand_3 ||
9938       tile == Xsand_stonesand_4)
9939     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9940 #endif
9941
9942 #if 1
9943   if (graphic_info[graphic].anim_global_sync)
9944     sync_frame = FrameCounter;
9945   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9946     sync_frame = GfxFrame[x][y];
9947   else
9948     sync_frame = 0;     /* playfield border (pseudo steel) */
9949
9950   SetRandomAnimationValue(x, y);
9951
9952   int frame = getAnimationFrame(g->anim_frames,
9953                                 g->anim_delay,
9954                                 g->anim_mode,
9955                                 g->anim_start_frame,
9956                                 sync_frame);
9957
9958   g_em->unique_identifier =
9959     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9960 #endif
9961 }
9962
9963 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9964                                   int tile, int frame_em, int x, int y)
9965 {
9966   int action = object_mapping[tile].action;
9967   int direction = object_mapping[tile].direction;
9968   boolean is_backside = object_mapping[tile].is_backside;
9969   int effective_element = get_effective_element_EM(tile, frame_em);
9970 #if 1
9971   int effective_action = action;
9972 #else
9973   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9974 #endif
9975   int graphic = (direction == MV_NONE ?
9976                  el_act2img(effective_element, effective_action) :
9977                  el_act_dir2img(effective_element, effective_action,
9978                                 direction));
9979   int crumbled = (direction == MV_NONE ?
9980                   el_act2crm(effective_element, effective_action) :
9981                   el_act_dir2crm(effective_element, effective_action,
9982                                  direction));
9983   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9984   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9985   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9986   struct GraphicInfo *g = &graphic_info[graphic];
9987 #if 0
9988   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9989 #endif
9990   int sync_frame;
9991
9992   /* special case: graphic uses "2nd movement tile" and has defined
9993      7 frames for movement animation (or less) => use default graphic
9994      for last (8th) frame which ends the movement animation */
9995   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9996   {
9997     effective_action = ACTION_DEFAULT;
9998     graphic = (direction == MV_NONE ?
9999                el_act2img(effective_element, effective_action) :
10000                el_act_dir2img(effective_element, effective_action,
10001                               direction));
10002     crumbled = (direction == MV_NONE ?
10003                 el_act2crm(effective_element, effective_action) :
10004                 el_act_dir2crm(effective_element, effective_action,
10005                                direction));
10006
10007     g = &graphic_info[graphic];
10008   }
10009
10010 #if 0
10011   if (frame_em == 7)
10012     return;
10013 #endif
10014
10015
10016 #if 0
10017   if (frame_em == 0)    /* reset animation frame for certain elements */
10018   {
10019     if (check_linear_animation_EM(tile))
10020       GfxFrame[x][y] = 0;
10021   }
10022 #endif
10023
10024   if (graphic_info[graphic].anim_global_sync)
10025     sync_frame = FrameCounter;
10026   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
10027     sync_frame = GfxFrame[x][y];
10028   else
10029     sync_frame = 0;     /* playfield border (pseudo steel) */
10030
10031   SetRandomAnimationValue(x, y);
10032
10033 #if 0
10034   int i = tile;
10035   int j = frame_em;
10036   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10037                         i == Xdrip_stretchB ? 7 :
10038                         i == Ydrip_s2 ? j + 8 :
10039                         i == Ydrip_s2B ? j + 8 :
10040                         i == Xacid_1 ? 0 :
10041                         i == Xacid_2 ? 10 :
10042                         i == Xacid_3 ? 20 :
10043                         i == Xacid_4 ? 30 :
10044                         i == Xacid_5 ? 40 :
10045                         i == Xacid_6 ? 50 :
10046                         i == Xacid_7 ? 60 :
10047                         i == Xacid_8 ? 70 :
10048                         i == Xfake_acid_1 ? 0 :
10049                         i == Xfake_acid_2 ? 10 :
10050                         i == Xfake_acid_3 ? 20 :
10051                         i == Xfake_acid_4 ? 30 :
10052                         i == Xfake_acid_5 ? 40 :
10053                         i == Xfake_acid_6 ? 50 :
10054                         i == Xfake_acid_7 ? 60 :
10055                         i == Xfake_acid_8 ? 70 :
10056                         i == Xball_2 ? 7 :
10057                         i == Xball_2B ? j + 8 :
10058                         i == Yball_eat ? j + 1 :
10059                         i == Ykey_1_eat ? j + 1 :
10060                         i == Ykey_2_eat ? j + 1 :
10061                         i == Ykey_3_eat ? j + 1 :
10062                         i == Ykey_4_eat ? j + 1 :
10063                         i == Ykey_5_eat ? j + 1 :
10064                         i == Ykey_6_eat ? j + 1 :
10065                         i == Ykey_7_eat ? j + 1 :
10066                         i == Ykey_8_eat ? j + 1 :
10067                         i == Ylenses_eat ? j + 1 :
10068                         i == Ymagnify_eat ? j + 1 :
10069                         i == Ygrass_eat ? j + 1 :
10070                         i == Ydirt_eat ? j + 1 :
10071                         i == Xamoeba_1 ? 0 :
10072                         i == Xamoeba_2 ? 1 :
10073                         i == Xamoeba_3 ? 2 :
10074                         i == Xamoeba_4 ? 3 :
10075                         i == Xamoeba_5 ? 0 :
10076                         i == Xamoeba_6 ? 1 :
10077                         i == Xamoeba_7 ? 2 :
10078                         i == Xamoeba_8 ? 3 :
10079                         i == Xexit_2 ? j + 8 :
10080                         i == Xexit_3 ? j + 16 :
10081                         i == Xdynamite_1 ? 0 :
10082                         i == Xdynamite_2 ? 8 :
10083                         i == Xdynamite_3 ? 16 :
10084                         i == Xdynamite_4 ? 24 :
10085                         i == Xsand_stonein_1 ? j + 1 :
10086                         i == Xsand_stonein_2 ? j + 9 :
10087                         i == Xsand_stonein_3 ? j + 17 :
10088                         i == Xsand_stonein_4 ? j + 25 :
10089                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10090                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10091                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10092                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10093                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10094                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10095                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10096                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10097                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10098                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10099                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10100                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10101                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10102                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10103                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10104                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10105                         i == Xboom_bug && j == 1 ? 2 :
10106                         i == Xboom_bug && j == 2 ? 2 :
10107                         i == Xboom_bug && j == 3 ? 4 :
10108                         i == Xboom_bug && j == 4 ? 4 :
10109                         i == Xboom_bug && j == 5 ? 2 :
10110                         i == Xboom_bug && j == 6 ? 2 :
10111                         i == Xboom_bug && j == 7 ? 0 :
10112                         i == Xboom_bomb && j == 1 ? 2 :
10113                         i == Xboom_bomb && j == 2 ? 2 :
10114                         i == Xboom_bomb && j == 3 ? 4 :
10115                         i == Xboom_bomb && j == 4 ? 4 :
10116                         i == Xboom_bomb && j == 5 ? 2 :
10117                         i == Xboom_bomb && j == 6 ? 2 :
10118                         i == Xboom_bomb && j == 7 ? 0 :
10119                         i == Xboom_android && j == 7 ? 6 :
10120                         i == Xboom_1 && j == 1 ? 2 :
10121                         i == Xboom_1 && j == 2 ? 2 :
10122                         i == Xboom_1 && j == 3 ? 4 :
10123                         i == Xboom_1 && j == 4 ? 4 :
10124                         i == Xboom_1 && j == 5 ? 6 :
10125                         i == Xboom_1 && j == 6 ? 6 :
10126                         i == Xboom_1 && j == 7 ? 8 :
10127                         i == Xboom_2 && j == 0 ? 8 :
10128                         i == Xboom_2 && j == 1 ? 8 :
10129                         i == Xboom_2 && j == 2 ? 10 :
10130                         i == Xboom_2 && j == 3 ? 10 :
10131                         i == Xboom_2 && j == 4 ? 10 :
10132                         i == Xboom_2 && j == 5 ? 12 :
10133                         i == Xboom_2 && j == 6 ? 12 :
10134                         i == Xboom_2 && j == 7 ? 12 :
10135 #if 0
10136                         special_animation && j == 4 ? 3 :
10137                         effective_action != action ? 0 :
10138 #endif
10139                         j);
10140 #endif
10141
10142 #if 0
10143   int xxx_effective_action;
10144   int xxx_has_action_graphics;
10145
10146   {
10147     int element = object_mapping[i].element_rnd;
10148     int action = object_mapping[i].action;
10149     int direction = object_mapping[i].direction;
10150     boolean is_backside = object_mapping[i].is_backside;
10151 #if 0
10152     boolean action_removing = (action == ACTION_DIGGING ||
10153                                action == ACTION_SNAPPING ||
10154                                action == ACTION_COLLECTING);
10155 #endif
10156     boolean action_exploding = ((action == ACTION_EXPLODING ||
10157                                  action == ACTION_SMASHED_BY_ROCK ||
10158                                  action == ACTION_SMASHED_BY_SPRING) &&
10159                                 element != EL_DIAMOND);
10160     boolean action_active = (action == ACTION_ACTIVE);
10161     boolean action_other = (action == ACTION_OTHER);
10162
10163     {
10164 #if 1
10165       int effective_element = get_effective_element_EM(i, j);
10166 #else
10167       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10168                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10169                                j < 7 ? element :
10170                                i == Xdrip_stretch ? element :
10171                                i == Xdrip_stretchB ? element :
10172                                i == Ydrip_s1 ? element :
10173                                i == Ydrip_s1B ? element :
10174                                i == Xball_1B ? element :
10175                                i == Xball_2 ? element :
10176                                i == Xball_2B ? element :
10177                                i == Yball_eat ? element :
10178                                i == Ykey_1_eat ? element :
10179                                i == Ykey_2_eat ? element :
10180                                i == Ykey_3_eat ? element :
10181                                i == Ykey_4_eat ? element :
10182                                i == Ykey_5_eat ? element :
10183                                i == Ykey_6_eat ? element :
10184                                i == Ykey_7_eat ? element :
10185                                i == Ykey_8_eat ? element :
10186                                i == Ylenses_eat ? element :
10187                                i == Ymagnify_eat ? element :
10188                                i == Ygrass_eat ? element :
10189                                i == Ydirt_eat ? element :
10190                                i == Yemerald_stone ? EL_EMERALD :
10191                                i == Ydiamond_stone ? EL_ROCK :
10192                                i == Xsand_stonein_1 ? element :
10193                                i == Xsand_stonein_2 ? element :
10194                                i == Xsand_stonein_3 ? element :
10195                                i == Xsand_stonein_4 ? element :
10196                                is_backside ? EL_EMPTY :
10197                                action_removing ? EL_EMPTY :
10198                                element);
10199 #endif
10200       int effective_action = (j < 7 ? action :
10201                               i == Xdrip_stretch ? action :
10202                               i == Xdrip_stretchB ? action :
10203                               i == Ydrip_s1 ? action :
10204                               i == Ydrip_s1B ? action :
10205                               i == Xball_1B ? action :
10206                               i == Xball_2 ? action :
10207                               i == Xball_2B ? action :
10208                               i == Yball_eat ? action :
10209                               i == Ykey_1_eat ? action :
10210                               i == Ykey_2_eat ? action :
10211                               i == Ykey_3_eat ? action :
10212                               i == Ykey_4_eat ? action :
10213                               i == Ykey_5_eat ? action :
10214                               i == Ykey_6_eat ? action :
10215                               i == Ykey_7_eat ? action :
10216                               i == Ykey_8_eat ? action :
10217                               i == Ylenses_eat ? action :
10218                               i == Ymagnify_eat ? action :
10219                               i == Ygrass_eat ? action :
10220                               i == Ydirt_eat ? action :
10221                               i == Xsand_stonein_1 ? action :
10222                               i == Xsand_stonein_2 ? action :
10223                               i == Xsand_stonein_3 ? action :
10224                               i == Xsand_stonein_4 ? action :
10225                               i == Xsand_stoneout_1 ? action :
10226                               i == Xsand_stoneout_2 ? action :
10227                               i == Xboom_android ? ACTION_EXPLODING :
10228                               action_exploding ? ACTION_EXPLODING :
10229                               action_active ? action :
10230                               action_other ? action :
10231                               ACTION_DEFAULT);
10232       int graphic = (el_act_dir2img(effective_element, effective_action,
10233                                     direction));
10234       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10235                                      direction));
10236       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10237       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10238       boolean has_action_graphics = (graphic != base_graphic);
10239       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10240       struct GraphicInfo *g = &graphic_info[graphic];
10241 #if 0
10242       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10243 #endif
10244       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10245       Bitmap *src_bitmap;
10246       int src_x, src_y;
10247       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10248       boolean special_animation = (action != ACTION_DEFAULT &&
10249                                    g->anim_frames == 3 &&
10250                                    g->anim_delay == 2 &&
10251                                    g->anim_mode & ANIM_LINEAR);
10252       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10253                         i == Xdrip_stretchB ? 7 :
10254                         i == Ydrip_s2 ? j + 8 :
10255                         i == Ydrip_s2B ? j + 8 :
10256                         i == Xacid_1 ? 0 :
10257                         i == Xacid_2 ? 10 :
10258                         i == Xacid_3 ? 20 :
10259                         i == Xacid_4 ? 30 :
10260                         i == Xacid_5 ? 40 :
10261                         i == Xacid_6 ? 50 :
10262                         i == Xacid_7 ? 60 :
10263                         i == Xacid_8 ? 70 :
10264                         i == Xfake_acid_1 ? 0 :
10265                         i == Xfake_acid_2 ? 10 :
10266                         i == Xfake_acid_3 ? 20 :
10267                         i == Xfake_acid_4 ? 30 :
10268                         i == Xfake_acid_5 ? 40 :
10269                         i == Xfake_acid_6 ? 50 :
10270                         i == Xfake_acid_7 ? 60 :
10271                         i == Xfake_acid_8 ? 70 :
10272                         i == Xball_2 ? 7 :
10273                         i == Xball_2B ? j + 8 :
10274                         i == Yball_eat ? j + 1 :
10275                         i == Ykey_1_eat ? j + 1 :
10276                         i == Ykey_2_eat ? j + 1 :
10277                         i == Ykey_3_eat ? j + 1 :
10278                         i == Ykey_4_eat ? j + 1 :
10279                         i == Ykey_5_eat ? j + 1 :
10280                         i == Ykey_6_eat ? j + 1 :
10281                         i == Ykey_7_eat ? j + 1 :
10282                         i == Ykey_8_eat ? j + 1 :
10283                         i == Ylenses_eat ? j + 1 :
10284                         i == Ymagnify_eat ? j + 1 :
10285                         i == Ygrass_eat ? j + 1 :
10286                         i == Ydirt_eat ? j + 1 :
10287                         i == Xamoeba_1 ? 0 :
10288                         i == Xamoeba_2 ? 1 :
10289                         i == Xamoeba_3 ? 2 :
10290                         i == Xamoeba_4 ? 3 :
10291                         i == Xamoeba_5 ? 0 :
10292                         i == Xamoeba_6 ? 1 :
10293                         i == Xamoeba_7 ? 2 :
10294                         i == Xamoeba_8 ? 3 :
10295                         i == Xexit_2 ? j + 8 :
10296                         i == Xexit_3 ? j + 16 :
10297                         i == Xdynamite_1 ? 0 :
10298                         i == Xdynamite_2 ? 8 :
10299                         i == Xdynamite_3 ? 16 :
10300                         i == Xdynamite_4 ? 24 :
10301                         i == Xsand_stonein_1 ? j + 1 :
10302                         i == Xsand_stonein_2 ? j + 9 :
10303                         i == Xsand_stonein_3 ? j + 17 :
10304                         i == Xsand_stonein_4 ? j + 25 :
10305                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10306                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10307                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10308                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10309                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10310                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10311                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10312                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10313                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10314                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10315                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10316                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10317                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10318                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10319                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10320                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10321                         i == Xboom_bug && j == 1 ? 2 :
10322                         i == Xboom_bug && j == 2 ? 2 :
10323                         i == Xboom_bug && j == 3 ? 4 :
10324                         i == Xboom_bug && j == 4 ? 4 :
10325                         i == Xboom_bug && j == 5 ? 2 :
10326                         i == Xboom_bug && j == 6 ? 2 :
10327                         i == Xboom_bug && j == 7 ? 0 :
10328                         i == Xboom_bomb && j == 1 ? 2 :
10329                         i == Xboom_bomb && j == 2 ? 2 :
10330                         i == Xboom_bomb && j == 3 ? 4 :
10331                         i == Xboom_bomb && j == 4 ? 4 :
10332                         i == Xboom_bomb && j == 5 ? 2 :
10333                         i == Xboom_bomb && j == 6 ? 2 :
10334                         i == Xboom_bomb && j == 7 ? 0 :
10335                         i == Xboom_android && j == 7 ? 6 :
10336                         i == Xboom_1 && j == 1 ? 2 :
10337                         i == Xboom_1 && j == 2 ? 2 :
10338                         i == Xboom_1 && j == 3 ? 4 :
10339                         i == Xboom_1 && j == 4 ? 4 :
10340                         i == Xboom_1 && j == 5 ? 6 :
10341                         i == Xboom_1 && j == 6 ? 6 :
10342                         i == Xboom_1 && j == 7 ? 8 :
10343                         i == Xboom_2 && j == 0 ? 8 :
10344                         i == Xboom_2 && j == 1 ? 8 :
10345                         i == Xboom_2 && j == 2 ? 10 :
10346                         i == Xboom_2 && j == 3 ? 10 :
10347                         i == Xboom_2 && j == 4 ? 10 :
10348                         i == Xboom_2 && j == 5 ? 12 :
10349                         i == Xboom_2 && j == 6 ? 12 :
10350                         i == Xboom_2 && j == 7 ? 12 :
10351                         special_animation && j == 4 ? 3 :
10352                         effective_action != action ? 0 :
10353                         j);
10354
10355       xxx_effective_action = effective_action;
10356       xxx_has_action_graphics = has_action_graphics;
10357     }
10358   }
10359 #endif
10360
10361   int frame = getAnimationFrame(g->anim_frames,
10362                                 g->anim_delay,
10363                                 g->anim_mode,
10364                                 g->anim_start_frame,
10365                                 sync_frame);
10366
10367
10368 #if 0
10369   return;
10370 #endif
10371
10372 #if 0
10373   if (frame_em == 7)
10374     return;
10375 #endif
10376
10377 #if 0
10378   int old_src_x = g_em->src_x;
10379   int old_src_y = g_em->src_y;
10380 #endif
10381
10382 #if 1
10383   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10384                       g->double_movement && is_backside);
10385 #else
10386   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10387                       &g_em->src_x, &g_em->src_y, FALSE);
10388 #endif
10389
10390
10391 #if 0
10392   if (tile == Ydiamond_stone)
10393     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10394            frame_em,
10395            g->anim_frames,
10396            g->anim_delay,
10397            g->anim_mode,
10398            g->anim_start_frame,
10399            sync_frame,
10400            frame,
10401            g_em->src_x, g_em->src_y,
10402            g_em->src_offset_x, g_em->src_offset_y,
10403            g_em->dst_offset_x, g_em->dst_offset_y,
10404            graphic);
10405 #endif
10406
10407
10408 #if 0
10409   return;
10410 #endif
10411
10412 #if 0
10413   if (frame_em == 7)
10414   {
10415     if (graphic == IMG_BUG_MOVING_RIGHT)
10416       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10417              g->double_movement, is_backside,
10418              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10419
10420     return;
10421   }
10422 #endif
10423
10424
10425 #if 0
10426   g_em->src_offset_x = 0;
10427   g_em->src_offset_y = 0;
10428   g_em->dst_offset_x = 0;
10429   g_em->dst_offset_y = 0;
10430   g_em->width  = TILEX;
10431   g_em->height = TILEY;
10432
10433   g_em->preserve_background = FALSE;
10434 #endif
10435
10436   /* (updating the "crumbled" graphic definitions is probably not really needed,
10437      as animations for crumbled graphics can't be longer than one EMC cycle) */
10438 #if 1
10439   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10440                            sync_frame);
10441
10442 #else
10443
10444   g_em->crumbled_bitmap = NULL;
10445   g_em->crumbled_src_x = 0;
10446   g_em->crumbled_src_y = 0;
10447
10448   g_em->has_crumbled_graphics = FALSE;
10449
10450   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10451   {
10452     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10453                                            g_crumbled->anim_delay,
10454                                            g_crumbled->anim_mode,
10455                                            g_crumbled->anim_start_frame,
10456                                            sync_frame);
10457
10458     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10459                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10460
10461     g_em->has_crumbled_graphics = TRUE;
10462   }
10463 #endif
10464
10465 #if 0
10466  {
10467    int effective_action = xxx_effective_action;
10468    int has_action_graphics = xxx_has_action_graphics;
10469
10470       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10471                                    effective_action == ACTION_MOVING  ||
10472                                    effective_action == ACTION_PUSHING ||
10473                                    effective_action == ACTION_EATING)) ||
10474           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10475                                     effective_action == ACTION_EMPTYING)))
10476       {
10477         int move_dir =
10478           (effective_action == ACTION_FALLING ||
10479            effective_action == ACTION_FILLING ||
10480            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10481         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10482         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10483         int num_steps = (i == Ydrip_s1  ? 16 :
10484                          i == Ydrip_s1B ? 16 :
10485                          i == Ydrip_s2  ? 16 :
10486                          i == Ydrip_s2B ? 16 :
10487                          i == Xsand_stonein_1 ? 32 :
10488                          i == Xsand_stonein_2 ? 32 :
10489                          i == Xsand_stonein_3 ? 32 :
10490                          i == Xsand_stonein_4 ? 32 :
10491                          i == Xsand_stoneout_1 ? 16 :
10492                          i == Xsand_stoneout_2 ? 16 : 8);
10493         int cx = ABS(dx) * (TILEX / num_steps);
10494         int cy = ABS(dy) * (TILEY / num_steps);
10495         int step_frame = (i == Ydrip_s2         ? j + 8 :
10496                           i == Ydrip_s2B        ? j + 8 :
10497                           i == Xsand_stonein_2  ? j + 8 :
10498                           i == Xsand_stonein_3  ? j + 16 :
10499                           i == Xsand_stonein_4  ? j + 24 :
10500                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10501         int step = (is_backside ? step_frame : num_steps - step_frame);
10502
10503         if (is_backside)        /* tile where movement starts */
10504         {
10505           if (dx < 0 || dy < 0)
10506           {
10507             g_em->src_offset_x = cx * step;
10508             g_em->src_offset_y = cy * step;
10509           }
10510           else
10511           {
10512             g_em->dst_offset_x = cx * step;
10513             g_em->dst_offset_y = cy * step;
10514           }
10515         }
10516         else                    /* tile where movement ends */
10517         {
10518           if (dx < 0 || dy < 0)
10519           {
10520             g_em->dst_offset_x = cx * step;
10521             g_em->dst_offset_y = cy * step;
10522           }
10523           else
10524           {
10525             g_em->src_offset_x = cx * step;
10526             g_em->src_offset_y = cy * step;
10527           }
10528         }
10529
10530         g_em->width  = TILEX - cx * step;
10531         g_em->height = TILEY - cy * step;
10532       }
10533
10534       /* create unique graphic identifier to decide if tile must be redrawn */
10535       /* bit 31 - 16 (16 bit): EM style graphic
10536          bit 15 - 12 ( 4 bit): EM style frame
10537          bit 11 -  6 ( 6 bit): graphic width
10538          bit  5 -  0 ( 6 bit): graphic height */
10539       g_em->unique_identifier =
10540         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10541  }
10542 #endif
10543
10544 }
10545
10546 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10547                                   int player_nr, int anim, int frame_em)
10548 {
10549   int element   = player_mapping[player_nr][anim].element_rnd;
10550   int action    = player_mapping[player_nr][anim].action;
10551   int direction = player_mapping[player_nr][anim].direction;
10552   int graphic = (direction == MV_NONE ?
10553                  el_act2img(element, action) :
10554                  el_act_dir2img(element, action, direction));
10555   struct GraphicInfo *g = &graphic_info[graphic];
10556   int sync_frame;
10557
10558   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10559
10560   stored_player[player_nr].StepFrame = frame_em;
10561
10562   sync_frame = stored_player[player_nr].Frame;
10563
10564   int frame = getAnimationFrame(g->anim_frames,
10565                                 g->anim_delay,
10566                                 g->anim_mode,
10567                                 g->anim_start_frame,
10568                                 sync_frame);
10569
10570   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10571                       &g_em->src_x, &g_em->src_y, FALSE);
10572
10573 #if 0
10574   printf("::: %d: %d, %d [%d]\n",
10575          player_nr,
10576          stored_player[player_nr].Frame,
10577          stored_player[player_nr].StepFrame,
10578          FrameCounter);
10579 #endif
10580 }
10581
10582 void InitGraphicInfo_EM(void)
10583 {
10584 #if 0
10585   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10586   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10587 #endif
10588   int i, j, p;
10589
10590 #if DEBUG_EM_GFX
10591   int num_em_gfx_errors = 0;
10592
10593   if (graphic_info_em_object[0][0].bitmap == NULL)
10594   {
10595     /* EM graphics not yet initialized in em_open_all() */
10596
10597     return;
10598   }
10599
10600   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10601 #endif
10602
10603   /* always start with reliable default values */
10604   for (i = 0; i < TILE_MAX; i++)
10605   {
10606     object_mapping[i].element_rnd = EL_UNKNOWN;
10607     object_mapping[i].is_backside = FALSE;
10608     object_mapping[i].action = ACTION_DEFAULT;
10609     object_mapping[i].direction = MV_NONE;
10610   }
10611
10612   /* always start with reliable default values */
10613   for (p = 0; p < MAX_PLAYERS; p++)
10614   {
10615     for (i = 0; i < SPR_MAX; i++)
10616     {
10617       player_mapping[p][i].element_rnd = EL_UNKNOWN;
10618       player_mapping[p][i].action = ACTION_DEFAULT;
10619       player_mapping[p][i].direction = MV_NONE;
10620     }
10621   }
10622
10623   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10624   {
10625     int e = em_object_mapping_list[i].element_em;
10626
10627     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10628     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10629
10630     if (em_object_mapping_list[i].action != -1)
10631       object_mapping[e].action = em_object_mapping_list[i].action;
10632
10633     if (em_object_mapping_list[i].direction != -1)
10634       object_mapping[e].direction =
10635         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10636   }
10637
10638   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10639   {
10640     int a = em_player_mapping_list[i].action_em;
10641     int p = em_player_mapping_list[i].player_nr;
10642
10643     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10644
10645     if (em_player_mapping_list[i].action != -1)
10646       player_mapping[p][a].action = em_player_mapping_list[i].action;
10647
10648     if (em_player_mapping_list[i].direction != -1)
10649       player_mapping[p][a].direction =
10650         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10651   }
10652
10653   for (i = 0; i < TILE_MAX; i++)
10654   {
10655     int element = object_mapping[i].element_rnd;
10656     int action = object_mapping[i].action;
10657     int direction = object_mapping[i].direction;
10658     boolean is_backside = object_mapping[i].is_backside;
10659 #if 0
10660     boolean action_removing = (action == ACTION_DIGGING ||
10661                                action == ACTION_SNAPPING ||
10662                                action == ACTION_COLLECTING);
10663 #endif
10664     boolean action_exploding = ((action == ACTION_EXPLODING ||
10665                                  action == ACTION_SMASHED_BY_ROCK ||
10666                                  action == ACTION_SMASHED_BY_SPRING) &&
10667                                 element != EL_DIAMOND);
10668     boolean action_active = (action == ACTION_ACTIVE);
10669     boolean action_other = (action == ACTION_OTHER);
10670
10671     for (j = 0; j < 8; j++)
10672     {
10673 #if 1
10674       int effective_element = get_effective_element_EM(i, j);
10675 #else
10676       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10677                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10678                                j < 7 ? element :
10679                                i == Xdrip_stretch ? element :
10680                                i == Xdrip_stretchB ? element :
10681                                i == Ydrip_s1 ? element :
10682                                i == Ydrip_s1B ? element :
10683                                i == Xball_1B ? element :
10684                                i == Xball_2 ? element :
10685                                i == Xball_2B ? element :
10686                                i == Yball_eat ? element :
10687                                i == Ykey_1_eat ? element :
10688                                i == Ykey_2_eat ? element :
10689                                i == Ykey_3_eat ? element :
10690                                i == Ykey_4_eat ? element :
10691                                i == Ykey_5_eat ? element :
10692                                i == Ykey_6_eat ? element :
10693                                i == Ykey_7_eat ? element :
10694                                i == Ykey_8_eat ? element :
10695                                i == Ylenses_eat ? element :
10696                                i == Ymagnify_eat ? element :
10697                                i == Ygrass_eat ? element :
10698                                i == Ydirt_eat ? element :
10699                                i == Yemerald_stone ? EL_EMERALD :
10700                                i == Ydiamond_stone ? EL_ROCK :
10701                                i == Xsand_stonein_1 ? element :
10702                                i == Xsand_stonein_2 ? element :
10703                                i == Xsand_stonein_3 ? element :
10704                                i == Xsand_stonein_4 ? element :
10705                                is_backside ? EL_EMPTY :
10706                                action_removing ? EL_EMPTY :
10707                                element);
10708 #endif
10709       int effective_action = (j < 7 ? action :
10710                               i == Xdrip_stretch ? action :
10711                               i == Xdrip_stretchB ? action :
10712                               i == Ydrip_s1 ? action :
10713                               i == Ydrip_s1B ? action :
10714                               i == Xball_1B ? action :
10715                               i == Xball_2 ? action :
10716                               i == Xball_2B ? action :
10717                               i == Yball_eat ? action :
10718                               i == Ykey_1_eat ? action :
10719                               i == Ykey_2_eat ? action :
10720                               i == Ykey_3_eat ? action :
10721                               i == Ykey_4_eat ? action :
10722                               i == Ykey_5_eat ? action :
10723                               i == Ykey_6_eat ? action :
10724                               i == Ykey_7_eat ? action :
10725                               i == Ykey_8_eat ? action :
10726                               i == Ylenses_eat ? action :
10727                               i == Ymagnify_eat ? action :
10728                               i == Ygrass_eat ? action :
10729                               i == Ydirt_eat ? action :
10730                               i == Xsand_stonein_1 ? action :
10731                               i == Xsand_stonein_2 ? action :
10732                               i == Xsand_stonein_3 ? action :
10733                               i == Xsand_stonein_4 ? action :
10734                               i == Xsand_stoneout_1 ? action :
10735                               i == Xsand_stoneout_2 ? action :
10736                               i == Xboom_android ? ACTION_EXPLODING :
10737                               action_exploding ? ACTION_EXPLODING :
10738                               action_active ? action :
10739                               action_other ? action :
10740                               ACTION_DEFAULT);
10741       int graphic = (el_act_dir2img(effective_element, effective_action,
10742                                     direction));
10743       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10744                                      direction));
10745       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10746       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10747       boolean has_action_graphics = (graphic != base_graphic);
10748       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10749       struct GraphicInfo *g = &graphic_info[graphic];
10750 #if 0
10751       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10752 #endif
10753       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10754       Bitmap *src_bitmap;
10755       int src_x, src_y;
10756       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10757       boolean special_animation = (action != ACTION_DEFAULT &&
10758                                    g->anim_frames == 3 &&
10759                                    g->anim_delay == 2 &&
10760                                    g->anim_mode & ANIM_LINEAR);
10761       int sync_frame = (i == Xdrip_stretch ? 7 :
10762                         i == Xdrip_stretchB ? 7 :
10763                         i == Ydrip_s2 ? j + 8 :
10764                         i == Ydrip_s2B ? j + 8 :
10765                         i == Xacid_1 ? 0 :
10766                         i == Xacid_2 ? 10 :
10767                         i == Xacid_3 ? 20 :
10768                         i == Xacid_4 ? 30 :
10769                         i == Xacid_5 ? 40 :
10770                         i == Xacid_6 ? 50 :
10771                         i == Xacid_7 ? 60 :
10772                         i == Xacid_8 ? 70 :
10773                         i == Xfake_acid_1 ? 0 :
10774                         i == Xfake_acid_2 ? 10 :
10775                         i == Xfake_acid_3 ? 20 :
10776                         i == Xfake_acid_4 ? 30 :
10777                         i == Xfake_acid_5 ? 40 :
10778                         i == Xfake_acid_6 ? 50 :
10779                         i == Xfake_acid_7 ? 60 :
10780                         i == Xfake_acid_8 ? 70 :
10781                         i == Xball_2 ? 7 :
10782                         i == Xball_2B ? j + 8 :
10783                         i == Yball_eat ? j + 1 :
10784                         i == Ykey_1_eat ? j + 1 :
10785                         i == Ykey_2_eat ? j + 1 :
10786                         i == Ykey_3_eat ? j + 1 :
10787                         i == Ykey_4_eat ? j + 1 :
10788                         i == Ykey_5_eat ? j + 1 :
10789                         i == Ykey_6_eat ? j + 1 :
10790                         i == Ykey_7_eat ? j + 1 :
10791                         i == Ykey_8_eat ? j + 1 :
10792                         i == Ylenses_eat ? j + 1 :
10793                         i == Ymagnify_eat ? j + 1 :
10794                         i == Ygrass_eat ? j + 1 :
10795                         i == Ydirt_eat ? j + 1 :
10796                         i == Xamoeba_1 ? 0 :
10797                         i == Xamoeba_2 ? 1 :
10798                         i == Xamoeba_3 ? 2 :
10799                         i == Xamoeba_4 ? 3 :
10800                         i == Xamoeba_5 ? 0 :
10801                         i == Xamoeba_6 ? 1 :
10802                         i == Xamoeba_7 ? 2 :
10803                         i == Xamoeba_8 ? 3 :
10804                         i == Xexit_2 ? j + 8 :
10805                         i == Xexit_3 ? j + 16 :
10806                         i == Xdynamite_1 ? 0 :
10807                         i == Xdynamite_2 ? 8 :
10808                         i == Xdynamite_3 ? 16 :
10809                         i == Xdynamite_4 ? 24 :
10810                         i == Xsand_stonein_1 ? j + 1 :
10811                         i == Xsand_stonein_2 ? j + 9 :
10812                         i == Xsand_stonein_3 ? j + 17 :
10813                         i == Xsand_stonein_4 ? j + 25 :
10814                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10815                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10816                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10817                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10818                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10819                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10820                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10821                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10822                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10823                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10824                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10825                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10826                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10827                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10828                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10829                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10830                         i == Xboom_bug && j == 1 ? 2 :
10831                         i == Xboom_bug && j == 2 ? 2 :
10832                         i == Xboom_bug && j == 3 ? 4 :
10833                         i == Xboom_bug && j == 4 ? 4 :
10834                         i == Xboom_bug && j == 5 ? 2 :
10835                         i == Xboom_bug && j == 6 ? 2 :
10836                         i == Xboom_bug && j == 7 ? 0 :
10837                         i == Xboom_bomb && j == 1 ? 2 :
10838                         i == Xboom_bomb && j == 2 ? 2 :
10839                         i == Xboom_bomb && j == 3 ? 4 :
10840                         i == Xboom_bomb && j == 4 ? 4 :
10841                         i == Xboom_bomb && j == 5 ? 2 :
10842                         i == Xboom_bomb && j == 6 ? 2 :
10843                         i == Xboom_bomb && j == 7 ? 0 :
10844                         i == Xboom_android && j == 7 ? 6 :
10845                         i == Xboom_1 && j == 1 ? 2 :
10846                         i == Xboom_1 && j == 2 ? 2 :
10847                         i == Xboom_1 && j == 3 ? 4 :
10848                         i == Xboom_1 && j == 4 ? 4 :
10849                         i == Xboom_1 && j == 5 ? 6 :
10850                         i == Xboom_1 && j == 6 ? 6 :
10851                         i == Xboom_1 && j == 7 ? 8 :
10852                         i == Xboom_2 && j == 0 ? 8 :
10853                         i == Xboom_2 && j == 1 ? 8 :
10854                         i == Xboom_2 && j == 2 ? 10 :
10855                         i == Xboom_2 && j == 3 ? 10 :
10856                         i == Xboom_2 && j == 4 ? 10 :
10857                         i == Xboom_2 && j == 5 ? 12 :
10858                         i == Xboom_2 && j == 6 ? 12 :
10859                         i == Xboom_2 && j == 7 ? 12 :
10860                         special_animation && j == 4 ? 3 :
10861                         effective_action != action ? 0 :
10862                         j);
10863
10864 #if DEBUG_EM_GFX
10865       Bitmap *debug_bitmap = g_em->bitmap;
10866       int debug_src_x = g_em->src_x;
10867       int debug_src_y = g_em->src_y;
10868 #endif
10869
10870       int frame = getAnimationFrame(g->anim_frames,
10871                                     g->anim_delay,
10872                                     g->anim_mode,
10873                                     g->anim_start_frame,
10874                                     sync_frame);
10875
10876       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10877                           g->double_movement && is_backside);
10878
10879       g_em->bitmap = src_bitmap;
10880       g_em->src_x = src_x;
10881       g_em->src_y = src_y;
10882       g_em->src_offset_x = 0;
10883       g_em->src_offset_y = 0;
10884       g_em->dst_offset_x = 0;
10885       g_em->dst_offset_y = 0;
10886       g_em->width  = TILEX;
10887       g_em->height = TILEY;
10888
10889       g_em->preserve_background = FALSE;
10890
10891 #if 1
10892       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10893                                sync_frame);
10894
10895 #else
10896
10897       g_em->crumbled_bitmap = NULL;
10898       g_em->crumbled_src_x = 0;
10899       g_em->crumbled_src_y = 0;
10900       g_em->crumbled_border_size = 0;
10901
10902       g_em->has_crumbled_graphics = FALSE;
10903
10904 #if 0
10905       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10906         printf("::: empty crumbled: %d [%s], %d, %d\n",
10907                effective_element, element_info[effective_element].token_name,
10908                effective_action, direction);
10909 #endif
10910
10911       /* if element can be crumbled, but certain action graphics are just empty
10912          space (like instantly snapping sand to empty space in 1 frame), do not
10913          treat these empty space graphics as crumbled graphics in EMC engine */
10914       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10915       {
10916         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10917                                                g_crumbled->anim_delay,
10918                                                g_crumbled->anim_mode,
10919                                                g_crumbled->anim_start_frame,
10920                                                sync_frame);
10921
10922         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10923
10924         g_em->has_crumbled_graphics = TRUE;
10925         g_em->crumbled_bitmap = src_bitmap;
10926         g_em->crumbled_src_x = src_x;
10927         g_em->crumbled_src_y = src_y;
10928         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10929
10930
10931 #if 0
10932         if (g_em == &graphic_info_em_object[207][0])
10933           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10934                  graphic_info_em_object[207][0].crumbled_src_x,
10935                  graphic_info_em_object[207][0].crumbled_src_y,
10936
10937                  crumbled, frame, src_x, src_y,
10938
10939                  g->anim_frames,
10940                  g->anim_delay,
10941                  g->anim_mode,
10942                  g->anim_start_frame,
10943                  sync_frame,
10944                  gfx.anim_random_frame,
10945                  frame);
10946 #endif
10947
10948 #if 0
10949         printf("::: EMC tile %d is crumbled\n", i);
10950 #endif
10951       }
10952 #endif
10953
10954 #if 0
10955       if (element == EL_ROCK &&
10956           effective_action == ACTION_FILLING)
10957         printf("::: has_action_graphics == %d\n", has_action_graphics);
10958 #endif
10959
10960       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10961                                    effective_action == ACTION_MOVING  ||
10962                                    effective_action == ACTION_PUSHING ||
10963                                    effective_action == ACTION_EATING)) ||
10964           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10965                                     effective_action == ACTION_EMPTYING)))
10966       {
10967         int move_dir =
10968           (effective_action == ACTION_FALLING ||
10969            effective_action == ACTION_FILLING ||
10970            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10971         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10972         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10973         int num_steps = (i == Ydrip_s1  ? 16 :
10974                          i == Ydrip_s1B ? 16 :
10975                          i == Ydrip_s2  ? 16 :
10976                          i == Ydrip_s2B ? 16 :
10977                          i == Xsand_stonein_1 ? 32 :
10978                          i == Xsand_stonein_2 ? 32 :
10979                          i == Xsand_stonein_3 ? 32 :
10980                          i == Xsand_stonein_4 ? 32 :
10981                          i == Xsand_stoneout_1 ? 16 :
10982                          i == Xsand_stoneout_2 ? 16 : 8);
10983         int cx = ABS(dx) * (TILEX / num_steps);
10984         int cy = ABS(dy) * (TILEY / num_steps);
10985         int step_frame = (i == Ydrip_s2         ? j + 8 :
10986                           i == Ydrip_s2B        ? j + 8 :
10987                           i == Xsand_stonein_2  ? j + 8 :
10988                           i == Xsand_stonein_3  ? j + 16 :
10989                           i == Xsand_stonein_4  ? j + 24 :
10990                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10991         int step = (is_backside ? step_frame : num_steps - step_frame);
10992
10993         if (is_backside)        /* tile where movement starts */
10994         {
10995           if (dx < 0 || dy < 0)
10996           {
10997             g_em->src_offset_x = cx * step;
10998             g_em->src_offset_y = cy * step;
10999           }
11000           else
11001           {
11002             g_em->dst_offset_x = cx * step;
11003             g_em->dst_offset_y = cy * step;
11004           }
11005         }
11006         else                    /* tile where movement ends */
11007         {
11008           if (dx < 0 || dy < 0)
11009           {
11010             g_em->dst_offset_x = cx * step;
11011             g_em->dst_offset_y = cy * step;
11012           }
11013           else
11014           {
11015             g_em->src_offset_x = cx * step;
11016             g_em->src_offset_y = cy * step;
11017           }
11018         }
11019
11020         g_em->width  = TILEX - cx * step;
11021         g_em->height = TILEY - cy * step;
11022       }
11023
11024       /* create unique graphic identifier to decide if tile must be redrawn */
11025       /* bit 31 - 16 (16 bit): EM style graphic
11026          bit 15 - 12 ( 4 bit): EM style frame
11027          bit 11 -  6 ( 6 bit): graphic width
11028          bit  5 -  0 ( 6 bit): graphic height */
11029       g_em->unique_identifier =
11030         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
11031
11032 #if DEBUG_EM_GFX
11033
11034       /* skip check for EMC elements not contained in original EMC artwork */
11035       if (element == EL_EMC_FAKE_ACID)
11036         continue;
11037
11038       if (g_em->bitmap != debug_bitmap ||
11039           g_em->src_x != debug_src_x ||
11040           g_em->src_y != debug_src_y ||
11041           g_em->src_offset_x != 0 ||
11042           g_em->src_offset_y != 0 ||
11043           g_em->dst_offset_x != 0 ||
11044           g_em->dst_offset_y != 0 ||
11045           g_em->width != TILEX ||
11046           g_em->height != TILEY)
11047       {
11048         static int last_i = -1;
11049
11050         if (i != last_i)
11051         {
11052           printf("\n");
11053           last_i = i;
11054         }
11055
11056         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
11057                i, element, element_info[element].token_name,
11058                element_action_info[effective_action].suffix, direction);
11059
11060         if (element != effective_element)
11061           printf(" [%d ('%s')]",
11062                  effective_element,
11063                  element_info[effective_element].token_name);
11064
11065         printf("\n");
11066
11067         if (g_em->bitmap != debug_bitmap)
11068           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
11069                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
11070
11071         if (g_em->src_x != debug_src_x ||
11072             g_em->src_y != debug_src_y)
11073           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11074                  j, (is_backside ? 'B' : 'F'),
11075                  g_em->src_x, g_em->src_y,
11076                  g_em->src_x / 32, g_em->src_y / 32,
11077                  debug_src_x, debug_src_y,
11078                  debug_src_x / 32, debug_src_y / 32);
11079
11080         if (g_em->src_offset_x != 0 ||
11081             g_em->src_offset_y != 0 ||
11082             g_em->dst_offset_x != 0 ||
11083             g_em->dst_offset_y != 0)
11084           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
11085                  j, is_backside,
11086                  g_em->src_offset_x, g_em->src_offset_y,
11087                  g_em->dst_offset_x, g_em->dst_offset_y);
11088
11089         if (g_em->width != TILEX ||
11090             g_em->height != TILEY)
11091           printf("    %d (%d): size %d,%d should be %d,%d\n",
11092                  j, is_backside,
11093                  g_em->width, g_em->height, TILEX, TILEY);
11094
11095         num_em_gfx_errors++;
11096       }
11097 #endif
11098
11099     }
11100   }
11101
11102   for (i = 0; i < TILE_MAX; i++)
11103   {
11104     for (j = 0; j < 8; j++)
11105     {
11106       int element = object_mapping[i].element_rnd;
11107       int action = object_mapping[i].action;
11108       int direction = object_mapping[i].direction;
11109       boolean is_backside = object_mapping[i].is_backside;
11110       int graphic_action  = el_act_dir2img(element, action, direction);
11111       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
11112
11113       if ((action == ACTION_SMASHED_BY_ROCK ||
11114            action == ACTION_SMASHED_BY_SPRING ||
11115            action == ACTION_EATING) &&
11116           graphic_action == graphic_default)
11117       {
11118         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
11119                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
11120                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
11121                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
11122                  Xspring);
11123
11124         /* no separate animation for "smashed by rock" -- use rock instead */
11125         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
11126         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
11127
11128         g_em->bitmap            = g_xx->bitmap;
11129         g_em->src_x             = g_xx->src_x;
11130         g_em->src_y             = g_xx->src_y;
11131         g_em->src_offset_x      = g_xx->src_offset_x;
11132         g_em->src_offset_y      = g_xx->src_offset_y;
11133         g_em->dst_offset_x      = g_xx->dst_offset_x;
11134         g_em->dst_offset_y      = g_xx->dst_offset_y;
11135         g_em->width             = g_xx->width;
11136         g_em->height            = g_xx->height;
11137         g_em->unique_identifier = g_xx->unique_identifier;
11138
11139         if (!is_backside)
11140           g_em->preserve_background = TRUE;
11141       }
11142     }
11143   }
11144
11145   for (p = 0; p < MAX_PLAYERS; p++)
11146   {
11147     for (i = 0; i < SPR_MAX; i++)
11148     {
11149       int element = player_mapping[p][i].element_rnd;
11150       int action = player_mapping[p][i].action;
11151       int direction = player_mapping[p][i].direction;
11152
11153       for (j = 0; j < 8; j++)
11154       {
11155         int effective_element = element;
11156         int effective_action = action;
11157         int graphic = (direction == MV_NONE ?
11158                        el_act2img(effective_element, effective_action) :
11159                        el_act_dir2img(effective_element, effective_action,
11160                                       direction));
11161         struct GraphicInfo *g = &graphic_info[graphic];
11162         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
11163         Bitmap *src_bitmap;
11164         int src_x, src_y;
11165         int sync_frame = j;
11166
11167 #if DEBUG_EM_GFX
11168         Bitmap *debug_bitmap = g_em->bitmap;
11169         int debug_src_x = g_em->src_x;
11170         int debug_src_y = g_em->src_y;
11171 #endif
11172
11173         int frame = getAnimationFrame(g->anim_frames,
11174                                       g->anim_delay,
11175                                       g->anim_mode,
11176                                       g->anim_start_frame,
11177                                       sync_frame);
11178
11179         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
11180
11181         g_em->bitmap = src_bitmap;
11182         g_em->src_x = src_x;
11183         g_em->src_y = src_y;
11184         g_em->src_offset_x = 0;
11185         g_em->src_offset_y = 0;
11186         g_em->dst_offset_x = 0;
11187         g_em->dst_offset_y = 0;
11188         g_em->width  = TILEX;
11189         g_em->height = TILEY;
11190
11191 #if DEBUG_EM_GFX
11192
11193         /* skip check for EMC elements not contained in original EMC artwork */
11194         if (element == EL_PLAYER_3 ||
11195             element == EL_PLAYER_4)
11196           continue;
11197
11198         if (g_em->bitmap != debug_bitmap ||
11199             g_em->src_x != debug_src_x ||
11200             g_em->src_y != debug_src_y)
11201         {
11202           static int last_i = -1;
11203
11204           if (i != last_i)
11205           {
11206             printf("\n");
11207             last_i = i;
11208           }
11209
11210           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11211                  p, i, element, element_info[element].token_name,
11212                  element_action_info[effective_action].suffix, direction);
11213
11214           if (element != effective_element)
11215             printf(" [%d ('%s')]",
11216                    effective_element,
11217                    element_info[effective_element].token_name);
11218
11219           printf("\n");
11220
11221           if (g_em->bitmap != debug_bitmap)
11222             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
11223                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
11224
11225           if (g_em->src_x != debug_src_x ||
11226               g_em->src_y != debug_src_y)
11227             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11228                    j,
11229                    g_em->src_x, g_em->src_y,
11230                    g_em->src_x / 32, g_em->src_y / 32,
11231                    debug_src_x, debug_src_y,
11232                    debug_src_x / 32, debug_src_y / 32);
11233
11234           num_em_gfx_errors++;
11235         }
11236 #endif
11237
11238       }
11239     }
11240   }
11241
11242 #if DEBUG_EM_GFX
11243   printf("\n");
11244   printf("::: [%d errors found]\n", num_em_gfx_errors);
11245
11246   exit(0);
11247 #endif
11248 }
11249
11250 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11251                             boolean any_player_moving,
11252                             boolean player_is_dropping)
11253 {
11254   if (tape.single_step && tape.recording && !tape.pausing)
11255   {
11256 #if 0
11257     boolean active_players = FALSE;
11258     int i;
11259
11260     for (i = 0; i < MAX_PLAYERS; i++)
11261       if (action[i] != JOY_NO_ACTION)
11262         active_players = TRUE;
11263 #endif
11264
11265     // if (frame == 0)
11266     if (frame == 0 && !player_is_dropping)
11267       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11268   }
11269 }
11270
11271 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11272                             boolean murphy_is_dropping)
11273 {
11274 #if 0
11275   printf("::: waiting: %d, dropping: %d\n",
11276          murphy_is_waiting, murphy_is_dropping);
11277 #endif
11278
11279   if (tape.single_step && tape.recording && !tape.pausing)
11280   {
11281     // if (murphy_is_waiting || murphy_is_dropping)
11282     if (murphy_is_waiting)
11283     {
11284 #if 0
11285       printf("::: murphy is waiting -> pause mode\n");
11286 #endif
11287
11288       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11289     }
11290   }
11291 }
11292
11293 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11294                          int graphic, int sync_frame, int x, int y)
11295 {
11296   int frame = getGraphicAnimationFrame(graphic, sync_frame);
11297
11298   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11299 }
11300
11301 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11302 {
11303   return (IS_NEXT_FRAME(sync_frame, graphic));
11304 }
11305
11306 int getGraphicInfo_Delay(int graphic)
11307 {
11308   return graphic_info[graphic].anim_delay;
11309 }
11310
11311 void PlayMenuSoundExt(int sound)
11312 {
11313   if (sound == SND_UNDEFINED)
11314     return;
11315
11316   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11317       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11318     return;
11319
11320   if (IS_LOOP_SOUND(sound))
11321     PlaySoundLoop(sound);
11322   else
11323     PlaySound(sound);
11324 }
11325
11326 void PlayMenuSound()
11327 {
11328   PlayMenuSoundExt(menu.sound[game_status]);
11329 }
11330
11331 void PlayMenuSoundStereo(int sound, int stereo_position)
11332 {
11333   if (sound == SND_UNDEFINED)
11334     return;
11335
11336   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11337       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11338     return;
11339
11340   if (IS_LOOP_SOUND(sound))
11341     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11342   else
11343     PlaySoundStereo(sound, stereo_position);
11344 }
11345
11346 void PlayMenuSoundIfLoopExt(int sound)
11347 {
11348   if (sound == SND_UNDEFINED)
11349     return;
11350
11351   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11352       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11353     return;
11354
11355   if (IS_LOOP_SOUND(sound))
11356     PlaySoundLoop(sound);
11357 }
11358
11359 void PlayMenuSoundIfLoop()
11360 {
11361   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11362 }
11363
11364 void PlayMenuMusicExt(int music)
11365 {
11366   if (music == MUS_UNDEFINED)
11367     return;
11368
11369   if (!setup.sound_music)
11370     return;
11371
11372   PlayMusic(music);
11373 }
11374
11375 void PlayMenuMusic()
11376 {
11377   PlayMenuMusicExt(menu.music[game_status]);
11378 }
11379
11380 void PlaySoundActivating()
11381 {
11382 #if 0
11383   PlaySound(SND_MENU_ITEM_ACTIVATING);
11384 #endif
11385 }
11386
11387 void PlaySoundSelecting()
11388 {
11389 #if 0
11390   PlaySound(SND_MENU_ITEM_SELECTING);
11391 #endif
11392 }
11393
11394 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11395 {
11396   boolean change_fullscreen = (setup.fullscreen !=
11397                                video.fullscreen_enabled);
11398   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11399                                     !strEqual(setup.fullscreen_mode,
11400                                               video.fullscreen_mode_current));
11401   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11402                                            setup.window_scaling_percent !=
11403                                            video.window_scaling_percent);
11404
11405   if (change_window_scaling_percent && video.fullscreen_enabled)
11406     return;
11407
11408   if (!change_window_scaling_percent && !video.fullscreen_available)
11409     return;
11410
11411 #if defined(TARGET_SDL2)
11412   if (change_window_scaling_percent)
11413   {
11414     SDLSetWindowScaling(setup.window_scaling_percent);
11415
11416     return;
11417   }
11418   else if (change_fullscreen)
11419   {
11420     SDLSetWindowFullscreen(setup.fullscreen);
11421
11422     /* set setup value according to successfully changed fullscreen mode */
11423     setup.fullscreen = video.fullscreen_enabled;
11424
11425     return;
11426   }
11427 #endif
11428
11429   if (change_fullscreen ||
11430       change_fullscreen_mode ||
11431       change_window_scaling_percent)
11432   {
11433     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11434
11435     /* save backbuffer content which gets lost when toggling fullscreen mode */
11436     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11437
11438     if (change_fullscreen_mode)
11439     {
11440       /* keep fullscreen, but change fullscreen mode (screen resolution) */
11441       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
11442     }
11443
11444     if (change_window_scaling_percent)
11445     {
11446       /* keep window mode, but change window scaling */
11447       video.fullscreen_enabled = TRUE;          /* force new window scaling */
11448     }
11449
11450     /* toggle fullscreen */
11451     ChangeVideoModeIfNeeded(setup.fullscreen);
11452
11453     /* set setup value according to successfully changed fullscreen mode */
11454     setup.fullscreen = video.fullscreen_enabled;
11455
11456     /* restore backbuffer content from temporary backbuffer backup bitmap */
11457     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11458
11459     FreeBitmap(tmp_backbuffer);
11460
11461 #if 1
11462     /* update visible window/screen */
11463     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11464 #else
11465     redraw_mask = REDRAW_ALL;
11466 #endif
11467   }
11468 }
11469
11470 void ChangeViewportPropertiesIfNeeded()
11471 {
11472 #if 0
11473   int *door_1_x = &DX;
11474   int *door_1_y = &DY;
11475   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11476   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11477 #endif
11478 #if 1
11479   int gfx_game_mode = game_status;
11480 #else
11481   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11482                        game_status == GAME_MODE_EDITOR ? game_status :
11483                        GAME_MODE_MAIN);
11484 #endif
11485   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11486                         game_status);
11487   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11488   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11489   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11490   struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11491   int border_size       = vp_playfield->border_size;
11492   int new_sx            = vp_playfield->x + border_size;
11493   int new_sy            = vp_playfield->y + border_size;
11494   int new_sxsize        = vp_playfield->width  - 2 * border_size;
11495   int new_sysize        = vp_playfield->height - 2 * border_size;
11496   int new_real_sx       = vp_playfield->x;
11497   int new_real_sy       = vp_playfield->y;
11498   int new_full_sxsize   = vp_playfield->width;
11499   int new_full_sysize   = vp_playfield->height;
11500   int new_dx            = vp_door_1->x;
11501   int new_dy            = vp_door_1->y;
11502   int new_dxsize        = vp_door_1->width;
11503   int new_dysize        = vp_door_1->height;
11504   int new_vx            = vp_door_2->x;
11505   int new_vy            = vp_door_2->y;
11506   int new_vxsize        = vp_door_2->width;
11507   int new_vysize        = vp_door_2->height;
11508   int new_ex            = vp_door_3->x;
11509   int new_ey            = vp_door_3->y;
11510   int new_exsize        = vp_door_3->width;
11511   int new_eysize        = vp_door_3->height;
11512 #if NEW_TILESIZE
11513   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11514   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11515                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11516   int new_scr_fieldx = new_sxsize / tilesize;
11517   int new_scr_fieldy = new_sysize / tilesize;
11518   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11519   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11520 #else
11521   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
11522   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11523 #endif
11524   boolean init_gfx_buffers = FALSE;
11525   boolean init_video_buffer = FALSE;
11526   boolean init_gadgets_and_toons = FALSE;
11527   boolean init_em_graphics = FALSE;
11528
11529 #if 0
11530   /* !!! TEST ONLY !!! */
11531   // InitGfxBuffers();
11532   return;
11533 #endif
11534
11535   if (viewport.window.width  != WIN_XSIZE ||
11536       viewport.window.height != WIN_YSIZE)
11537   {
11538     WIN_XSIZE = viewport.window.width;
11539     WIN_YSIZE = viewport.window.height;
11540
11541 #if 1
11542     init_video_buffer = TRUE;
11543     init_gfx_buffers = TRUE;
11544 #else
11545     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11546     InitGfxBuffers();
11547
11548 #if 1
11549     SetDrawDeactivationMask(REDRAW_NONE);
11550     SetDrawBackgroundMask(REDRAW_FIELD);
11551
11552     // RedrawBackground();
11553 #endif
11554 #endif
11555
11556     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11557   }
11558
11559   if (new_scr_fieldx != SCR_FIELDX ||
11560       new_scr_fieldy != SCR_FIELDY)
11561   {
11562     /* this always toggles between MAIN and GAME when using small tile size */
11563
11564     SCR_FIELDX = new_scr_fieldx;
11565     SCR_FIELDY = new_scr_fieldy;
11566
11567     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11568   }
11569
11570 #if 0
11571   if (new_tilesize_var != TILESIZE_VAR &&
11572       gfx_game_mode == GAME_MODE_PLAYING)
11573   {
11574     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11575
11576     TILESIZE_VAR = new_tilesize_var;
11577
11578     init_gfx_buffers = TRUE;
11579
11580     // printf("::: tilesize: init_gfx_buffers\n");
11581   }
11582 #endif
11583
11584   if (new_sx != SX ||
11585       new_sy != SY ||
11586       new_dx != DX ||
11587       new_dy != DY ||
11588       new_vx != VX ||
11589       new_vy != VY ||
11590       new_ex != EX ||
11591       new_ey != EY ||
11592       new_sxsize != SXSIZE ||
11593       new_sysize != SYSIZE ||
11594       new_dxsize != DXSIZE ||
11595       new_dysize != DYSIZE ||
11596       new_vxsize != VXSIZE ||
11597       new_vysize != VYSIZE ||
11598       new_exsize != EXSIZE ||
11599       new_eysize != EYSIZE ||
11600       new_real_sx != REAL_SX ||
11601       new_real_sy != REAL_SY ||
11602       new_full_sxsize != FULL_SXSIZE ||
11603       new_full_sysize != FULL_SYSIZE ||
11604       new_tilesize_var != TILESIZE_VAR
11605 #if 0
11606       ||
11607       vp_door_1->x != *door_1_x ||
11608       vp_door_1->y != *door_1_y ||
11609       vp_door_2->x != *door_2_x ||
11610       vp_door_2->y != *door_2_y
11611 #endif
11612       )
11613   {
11614 #if 1
11615     if (new_tilesize_var != TILESIZE_VAR)
11616     {
11617       // printf("::: new_tilesize_var != TILESIZE_VAR\n");
11618
11619       // changing tile size invalidates scroll values of engine snapshots
11620       FreeEngineSnapshot();
11621
11622       // changing tile size requires update of graphic mapping for EM engine
11623       init_em_graphics = TRUE;
11624     }
11625 #endif
11626
11627     SX = new_sx;
11628     SY = new_sy;
11629     DX = new_dx;
11630     DY = new_dy;
11631     VX = new_vx;
11632     VY = new_vy;
11633     EX = new_ex;
11634     EY = new_ey;
11635     SXSIZE = new_sxsize;
11636     SYSIZE = new_sysize;
11637     DXSIZE = new_dxsize;
11638     DYSIZE = new_dysize;
11639     VXSIZE = new_vxsize;
11640     VYSIZE = new_vysize;
11641     EXSIZE = new_exsize;
11642     EYSIZE = new_eysize;
11643     REAL_SX = new_real_sx;
11644     REAL_SY = new_real_sy;
11645     FULL_SXSIZE = new_full_sxsize;
11646     FULL_SYSIZE = new_full_sysize;
11647     TILESIZE_VAR = new_tilesize_var;
11648
11649 #if 0
11650     printf("::: %d, %d, %d [%d]\n",
11651            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11652            setup.small_game_graphics);
11653 #endif
11654
11655 #if 0
11656     *door_1_x = vp_door_1->x;
11657     *door_1_y = vp_door_1->y;
11658     *door_2_x = vp_door_2->x;
11659     *door_2_y = vp_door_2->y;
11660 #endif
11661
11662 #if 1
11663     init_gfx_buffers = TRUE;
11664
11665     // printf("::: viewports: init_gfx_buffers\n");
11666 #else
11667     InitGfxBuffers();
11668 #endif
11669
11670 #if 0
11671     if (gfx_game_mode == GAME_MODE_MAIN)
11672 #endif
11673     {
11674 #if 1
11675       init_gadgets_and_toons = TRUE;
11676
11677       // printf("::: viewports: init_gadgets_and_toons\n");
11678 #else
11679       InitGadgets();
11680       InitToons();
11681 #endif
11682     }
11683   }
11684
11685   if (init_gfx_buffers)
11686   {
11687     // printf("::: init_gfx_buffers\n");
11688
11689     SCR_FIELDX = new_scr_fieldx_buffers;
11690     SCR_FIELDY = new_scr_fieldy_buffers;
11691
11692     InitGfxBuffers();
11693
11694     SCR_FIELDX = new_scr_fieldx;
11695     SCR_FIELDY = new_scr_fieldy;
11696   }
11697
11698   if (init_video_buffer)
11699   {
11700     // printf("::: init_video_buffer\n");
11701
11702     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11703
11704     SetDrawDeactivationMask(REDRAW_NONE);
11705     SetDrawBackgroundMask(REDRAW_FIELD);
11706   }
11707
11708   if (init_gadgets_and_toons)
11709   {
11710     // printf("::: init_gadgets_and_toons\n");
11711
11712     InitGadgets();
11713     InitToons();
11714   }
11715
11716   if (init_em_graphics)
11717   {
11718       InitGraphicInfo_EM();
11719   }
11720
11721 #if 0
11722   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
11723 #endif
11724 }