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