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