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