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