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