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