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