rnd_jue-3.2.5
[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 "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "game.h"
18 #include "events.h"
19 #include "cartoons.h"
20 #include "network.h"
21 #include "tape.h"
22 #include "screens.h"
23
24
25 /* select level set with EMC X11 graphics before activating EM GFX debugging */
26 #define DEBUG_EM_GFX    0
27
28 /* tool button identifiers */
29 #define TOOL_CTRL_ID_YES        0
30 #define TOOL_CTRL_ID_NO         1
31 #define TOOL_CTRL_ID_CONFIRM    2
32 #define TOOL_CTRL_ID_PLAYER_1   3
33 #define TOOL_CTRL_ID_PLAYER_2   4
34 #define TOOL_CTRL_ID_PLAYER_3   5
35 #define TOOL_CTRL_ID_PLAYER_4   6
36
37 #define NUM_TOOL_BUTTONS        7
38
39 /* forward declaration for internal use */
40 static void UnmapToolButtons();
41 static void HandleToolButtons(struct GadgetInfo *);
42 static int el_act_dir2crm(int, int, int);
43 static int el_act2crm(int, int);
44
45 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
46 static int request_gadget_id = -1;
47
48 static char *print_if_not_empty(int element)
49 {
50   static char *s = NULL;
51   char *token_name = element_info[element].token_name;
52
53   if (s != NULL)
54     free(s);
55
56   s = checked_malloc(strlen(token_name) + 10 + 1);
57
58   if (element != EL_EMPTY)
59     sprintf(s, "%d\t['%s']", element, token_name);
60   else
61     sprintf(s, "%d", element);
62
63   return s;
64 }
65
66 void DumpTile(int x, int y)
67 {
68   int sx = SCREENX(x);
69   int sy = SCREENY(y);
70
71   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
72   {
73     x--;
74     y--;
75   }
76
77   printf_line("-", 79);
78   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
79   printf_line("-", 79);
80
81   if (!IN_LEV_FIELD(x, y))
82   {
83     printf("(not in level field)\n");
84     printf("\n");
85
86     return;
87   }
88
89   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
90          element_info[Feld[x][y]].token_name);
91   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
92   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
93   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
94   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
95   printf("  MovPos:      %d\n", MovPos[x][y]);
96   printf("  MovDir:      %d\n", MovDir[x][y]);
97   printf("  MovDelay:    %d\n", MovDelay[x][y]);
98   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
99   printf("  CustomValue: %d\n", CustomValue[x][y]);
100   printf("  GfxElement:  %d\n", GfxElement[x][y]);
101   printf("  GfxAction:   %d\n", GfxAction[x][y]);
102   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
103   printf("\n");
104 }
105
106 void SetDrawtoField(int mode)
107 {
108   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
109   {
110     FX = TILEX;
111     FY = TILEY;
112     BX1 = -1;
113     BY1 = -1;
114     BX2 = SCR_FIELDX;
115     BY2 = SCR_FIELDY;
116     redraw_x1 = 1;
117     redraw_y1 = 1;
118
119     drawto_field = fieldbuffer;
120   }
121   else  /* DRAW_BACKBUFFER */
122   {
123     FX = SX;
124     FY = SY;
125     BX1 = 0;
126     BY1 = 0;
127     BX2 = SCR_FIELDX - 1;
128     BY2 = SCR_FIELDY - 1;
129     redraw_x1 = 0;
130     redraw_y1 = 0;
131
132     drawto_field = backbuffer;
133   }
134 }
135
136 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
137 {
138   if (game_status == GAME_MODE_PLAYING &&
139       level.game_engine_type == GAME_ENGINE_TYPE_EM)
140   {
141     /* currently there is no partial redraw -- always redraw whole playfield */
142     RedrawPlayfield_EM(TRUE);
143
144     /* blit playfield from scroll buffer to normal back buffer for fading in */
145     BlitScreenToBitmap_EM(backbuffer);
146   }
147   else if (game_status == GAME_MODE_PLAYING && !game.envelope_active)
148   {
149     if (force_redraw)
150     {
151       x = gfx.sx - TILEX;
152       y = gfx.sy - TILEY;
153       width = gfx.sxsize + 2 * TILEX;
154       height = gfx.sysize + 2 * TILEY;
155     }
156
157     if (force_redraw)
158     {
159       int xx, yy;
160       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
161       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
162
163       for (xx = BX1; xx <= BX2; xx++)
164         for (yy = BY1; yy <= BY2; yy++)
165           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
166             DrawScreenField(xx, yy);
167       DrawAllPlayers();
168     }
169
170     if (setup.soft_scrolling)
171     {
172       int fx = FX, fy = FY;
173
174       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
175       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
176
177       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
178     }
179   }
180
181   if (force_redraw)
182   {
183     x = gfx.sx;
184     y = gfx.sy;
185     width = gfx.sxsize;
186     height = gfx.sysize;
187   }
188
189   BlitBitmap(drawto, window, x, y, width, height, x, y);
190 }
191
192 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
193 {
194   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
195
196   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
197   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
198 }
199
200 void DrawMaskedBorder_FIELD()
201 {
202   if (global.border_status >= GAME_MODE_TITLE &&
203       global.border_status <= GAME_MODE_PLAYING &&
204       border.draw_masked[global.border_status])
205     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
206 }
207
208 void DrawMaskedBorder_DOOR_1()
209 {
210   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
211       (global.border_status != GAME_MODE_EDITOR ||
212        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
213     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
214 }
215
216 void DrawMaskedBorder_DOOR_2()
217 {
218   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
219       global.border_status != GAME_MODE_EDITOR)
220     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
221 }
222
223 void DrawMaskedBorder_DOOR_3()
224 {
225   /* currently not available */
226 }
227
228 void DrawMaskedBorder_ALL()
229 {
230   DrawMaskedBorder_FIELD();
231   DrawMaskedBorder_DOOR_1();
232   DrawMaskedBorder_DOOR_2();
233   DrawMaskedBorder_DOOR_3();
234 }
235
236 void DrawMaskedBorder(int redraw_mask)
237 {
238   /* never draw masked screen borders on borderless screens */
239   if (effectiveGameStatus() == GAME_MODE_LOADING ||
240       effectiveGameStatus() == GAME_MODE_TITLE)
241     return;
242
243   if (redraw_mask & REDRAW_ALL)
244     DrawMaskedBorder_ALL();
245   else
246   {
247     if (redraw_mask & REDRAW_FIELD)
248       DrawMaskedBorder_FIELD();
249     if (redraw_mask & REDRAW_DOOR_1)
250       DrawMaskedBorder_DOOR_1();
251     if (redraw_mask & REDRAW_DOOR_2)
252       DrawMaskedBorder_DOOR_2();
253     if (redraw_mask & REDRAW_DOOR_3)
254       DrawMaskedBorder_DOOR_3();
255   }
256 }
257
258 void BackToFront()
259 {
260   int x, y;
261   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
262
263 #if 0
264   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
265   for (x = 0; x < SCR_FIELDX; x++)
266     for (y = 0 ; y < SCR_FIELDY; y++)
267       if (redraw[redraw_x1 + x][redraw_y1 + y])
268         printf("::: - %d, %d [%s]\n",
269                LEVELX(x), LEVELY(y),
270                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
271 #endif
272
273   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
274     redraw_mask |= REDRAW_FIELD;
275
276   if (redraw_mask & REDRAW_FIELD)
277     redraw_mask &= ~REDRAW_TILES;
278
279   if (redraw_mask == REDRAW_NONE)
280     return;
281
282   if (redraw_mask & REDRAW_TILES &&
283       game_status == GAME_MODE_PLAYING &&
284       border.draw_masked[GAME_MODE_PLAYING])
285     redraw_mask |= REDRAW_FIELD;
286
287   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
288   {
289     static boolean last_frame_skipped = FALSE;
290     boolean skip_even_when_not_scrolling = TRUE;
291     boolean just_scrolling = (ScreenMovDir != 0);
292     boolean verbose = FALSE;
293
294     if (global.fps_slowdown_factor > 1 &&
295         (FrameCounter % global.fps_slowdown_factor) &&
296         (just_scrolling || skip_even_when_not_scrolling))
297     {
298       redraw_mask &= ~REDRAW_MAIN;
299
300       last_frame_skipped = TRUE;
301
302       if (verbose)
303         printf("FRAME SKIPPED\n");
304     }
305     else
306     {
307       if (last_frame_skipped)
308         redraw_mask |= REDRAW_FIELD;
309
310       last_frame_skipped = FALSE;
311
312       if (verbose)
313         printf("frame not skipped\n");
314     }
315   }
316
317   /* synchronize X11 graphics at this point; if we would synchronize the
318      display immediately after the buffer switching (after the XFlush),
319      this could mean that we have to wait for the graphics to complete,
320      although we could go on doing calculations for the next frame */
321
322   SyncDisplay();
323
324   /* prevent drawing masked border to backbuffer when using playfield buffer */
325   if (game_status != GAME_MODE_PLAYING ||
326       redraw_mask & REDRAW_FROM_BACKBUFFER ||
327       buffer == backbuffer)
328     DrawMaskedBorder(redraw_mask);
329   else
330     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
331
332   if (redraw_mask & REDRAW_ALL)
333   {
334     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
335
336     redraw_mask = REDRAW_NONE;
337   }
338
339   if (redraw_mask & REDRAW_FIELD)
340   {
341     if (game_status != GAME_MODE_PLAYING ||
342         redraw_mask & REDRAW_FROM_BACKBUFFER)
343     {
344       BlitBitmap(backbuffer, window,
345                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
346     }
347     else
348     {
349       int fx = FX, fy = FY;
350
351       if (setup.soft_scrolling)
352       {
353         fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
354         fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
355       }
356
357       if (setup.soft_scrolling ||
358           ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
359           ABS(ScreenMovPos) == ScrollStepSize ||
360           redraw_tiles > REDRAWTILES_THRESHOLD)
361       {
362         if (border.draw_masked[GAME_MODE_PLAYING])
363         {
364           if (buffer != backbuffer)
365           {
366             /* copy playfield buffer to backbuffer to add masked border */
367             BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
368             DrawMaskedBorder(REDRAW_FIELD);
369           }
370
371           BlitBitmap(backbuffer, window,
372                      REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
373                      REAL_SX, REAL_SY);
374         }
375         else
376         {
377           BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
378         }
379
380 #if 0
381 #ifdef DEBUG
382         printf("redrawing all (ScreenGfxPos == %d) because %s\n",
383                ScreenGfxPos,
384                (setup.soft_scrolling ?
385                 "setup.soft_scrolling" :
386                 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
387                 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
388                 ABS(ScreenGfxPos) == ScrollStepSize ?
389                 "ABS(ScreenGfxPos) == ScrollStepSize" :
390                 "redraw_tiles > REDRAWTILES_THRESHOLD"));
391 #endif
392 #endif
393       }
394     }
395
396     redraw_mask &= ~REDRAW_MAIN;
397   }
398
399   if (redraw_mask & REDRAW_DOORS)
400   {
401     if (redraw_mask & REDRAW_DOOR_1)
402       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
403
404     if (redraw_mask & REDRAW_DOOR_2)
405       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
406
407     if (redraw_mask & REDRAW_DOOR_3)
408       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
409
410     redraw_mask &= ~REDRAW_DOORS;
411   }
412
413   if (redraw_mask & REDRAW_MICROLEVEL)
414   {
415     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
416                SX, SY + 10 * TILEY);
417
418     redraw_mask &= ~REDRAW_MICROLEVEL;
419   }
420
421   if (redraw_mask & REDRAW_TILES)
422   {
423     for (x = 0; x < SCR_FIELDX; x++)
424       for (y = 0 ; y < SCR_FIELDY; y++)
425         if (redraw[redraw_x1 + x][redraw_y1 + y])
426           BlitBitmap(buffer, window,
427                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
428                      SX + x * TILEX, SY + y * TILEY);
429   }
430
431   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
432   {
433     char text[100];
434     char info1[100];
435
436     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
437     if (!global.fps_slowdown)
438       info1[0] = '\0';
439
440     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
441 #if 1
442     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
443 #else
444     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
445 #endif
446   }
447
448   FlushDisplay();
449
450   for (x = 0; x < MAX_BUF_XSIZE; x++)
451     for (y = 0; y < MAX_BUF_YSIZE; y++)
452       redraw[x][y] = 0;
453   redraw_tiles = 0;
454   redraw_mask = REDRAW_NONE;
455 }
456
457 static void FadeCrossSaveBackbuffer()
458 {
459   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
460 }
461
462 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
463 {
464   static int fade_type_skip = FADE_TYPE_NONE;
465   void (*draw_border_function)(void) = NULL;
466   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
467   int x, y, width, height;
468   int fade_delay, post_delay;
469
470   if (fade_type == FADE_TYPE_FADE_OUT)
471   {
472     if (fade_type_skip != FADE_TYPE_NONE)
473     {
474 #if 0
475       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
476 #endif
477
478       /* skip all fade operations until specified fade operation */
479       if (fade_type & fade_type_skip)
480         fade_type_skip = FADE_TYPE_NONE;
481
482       return;
483     }
484
485     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
486     {
487       FadeCrossSaveBackbuffer();
488
489       return;
490     }
491   }
492
493   redraw_mask |= fade_mask;
494
495   if (fade_type == FADE_TYPE_SKIP)
496   {
497 #if 0
498     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
499 #endif
500
501     fade_type_skip = fade_mode;
502
503     return;
504   }
505
506   if (fade_type_skip != FADE_TYPE_NONE)
507   {
508 #if 0
509     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
510 #endif
511
512     /* skip all fade operations until specified fade operation */
513     if (fade_type & fade_type_skip)
514       fade_type_skip = FADE_TYPE_NONE;
515
516     return;
517   }
518
519 #if 1
520   if (global.autoplay_leveldir)
521   {
522     // fading.fade_mode = FADE_MODE_NONE;
523
524     return;
525   }
526 #endif
527
528 #if 0
529   if (fading.fade_mode == FADE_MODE_NONE)
530   {
531     BackToFront();
532
533     return;
534   }
535 #endif
536
537   /* !!! what abount fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
538
539 #if 0
540   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
541 #endif
542
543 #if 0
544   if (fade_mask == REDRAW_NONE)
545     fade_mask = REDRAW_FIELD;
546 #endif
547
548   // if (fade_mask & REDRAW_FIELD)
549   if (fade_mask == REDRAW_FIELD)
550   {
551     x = REAL_SX;
552     y = REAL_SY;
553     width  = FULL_SXSIZE;
554     height = FULL_SYSIZE;
555
556     fade_delay = fading.fade_delay;
557     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
558
559     if (border.draw_masked_when_fading)
560       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
561     else
562       DrawMaskedBorder_FIELD();                         /* draw once */
563   }
564   else          /* REDRAW_ALL */
565   {
566     x = 0;
567     y = 0;
568     width  = WIN_XSIZE;
569     height = WIN_YSIZE;
570
571     fade_delay = fading.fade_delay;
572     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
573   }
574
575 #if 1
576   if (!setup.fade_screens ||
577       fade_delay == 0 ||
578       fading.fade_mode == FADE_MODE_NONE)
579 #else
580   if (!setup.fade_screens || fade_delay == 0)
581 #endif
582   {
583     if (fade_mode == FADE_MODE_FADE_OUT)
584       return;
585
586 #if 0
587     if (fade_mode == FADE_MODE_FADE_OUT &&
588         fading.fade_mode != FADE_MODE_NONE)
589       ClearRectangle(backbuffer, x, y, width, height);
590 #endif
591
592 #if 1
593     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
594     redraw_mask = REDRAW_NONE;
595 #else
596     BackToFront();
597 #endif
598
599     return;
600   }
601
602   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
603                 draw_border_function);
604
605   redraw_mask &= ~fade_mask;
606 }
607
608 void FadeIn(int fade_mask)
609 {
610   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
611     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
612   else
613     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
614 }
615
616 void FadeOut(int fade_mask)
617 {
618   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
619     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
620   else
621     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
622
623   global.border_status = game_status;
624 }
625
626 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
627 {
628   static struct TitleFadingInfo fading_leave_stored;
629
630   if (set)
631     fading_leave_stored = fading_leave;
632   else
633     fading = fading_leave_stored;
634 }
635
636 void FadeSetEnterMenu()
637 {
638   fading = menu.enter_menu;
639
640 #if 0
641   printf("::: storing enter_menu\n");
642 #endif
643
644   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
645 }
646
647 void FadeSetLeaveMenu()
648 {
649   fading = menu.leave_menu;
650
651 #if 0
652   printf("::: storing leave_menu\n");
653 #endif
654
655   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
656 }
657
658 void FadeSetEnterScreen()
659 {
660   fading = menu.enter_screen[game_status];
661
662 #if 0
663   printf("::: storing leave_screen[%d]\n", game_status);
664 #endif
665
666   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
667 }
668
669 void FadeSetNextScreen()
670 {
671   fading = menu.next_screen;
672
673 #if 0
674   printf("::: storing next_screen\n");
675 #endif
676
677   // (do not overwrite fade mode set by FadeSetEnterScreen)
678   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
679 }
680
681 void FadeSetLeaveScreen()
682 {
683 #if 0
684   printf("::: recalling last stored value\n");
685 #endif
686
687   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
688 }
689
690 void FadeSetFromType(int type)
691 {
692   if (type & TYPE_ENTER_SCREEN)
693     FadeSetEnterScreen();
694   else if (type & TYPE_ENTER)
695     FadeSetEnterMenu();
696   else if (type & TYPE_LEAVE)
697     FadeSetLeaveMenu();
698 }
699
700 void FadeSetDisabled()
701 {
702   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
703
704   fading = fading_none;
705 }
706
707 void FadeSkipNextFadeIn()
708 {
709   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
710 }
711
712 void FadeSkipNextFadeOut()
713 {
714   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
715 }
716
717 void SetWindowBackgroundImageIfDefined(int graphic)
718 {
719   if (graphic_info[graphic].bitmap)
720     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
721 }
722
723 void SetMainBackgroundImageIfDefined(int graphic)
724 {
725   if (graphic_info[graphic].bitmap)
726     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
727 }
728
729 void SetDoorBackgroundImageIfDefined(int graphic)
730 {
731   if (graphic_info[graphic].bitmap)
732     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
733 }
734
735 void SetWindowBackgroundImage(int graphic)
736 {
737   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
738                             graphic_info[graphic].bitmap ?
739                             graphic_info[graphic].bitmap :
740                             graphic_info[IMG_BACKGROUND].bitmap);
741 }
742
743 void SetMainBackgroundImage(int graphic)
744 {
745   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
746                           graphic_info[graphic].bitmap ?
747                           graphic_info[graphic].bitmap :
748                           graphic_info[IMG_BACKGROUND].bitmap);
749 }
750
751 void SetDoorBackgroundImage(int graphic)
752 {
753   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
754                           graphic_info[graphic].bitmap ?
755                           graphic_info[graphic].bitmap :
756                           graphic_info[IMG_BACKGROUND].bitmap);
757 }
758
759 void SetPanelBackground()
760 {
761   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
762              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
763
764   SetDoorBackgroundBitmap(bitmap_db_panel);
765 }
766
767 void DrawBackground(int x, int y, int width, int height)
768 {
769   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
770   /* (when entering hall of fame after playing) */
771 #if 0
772   ClearRectangleOnBackground(drawto, x, y, width, height);
773 #else
774   ClearRectangleOnBackground(backbuffer, x, y, width, height);
775 #endif
776
777   redraw_mask |= REDRAW_FIELD;
778 }
779
780 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
781 {
782   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
783
784   if (font->bitmap == NULL)
785     return;
786
787   DrawBackground(x, y, width, height);
788 }
789
790 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
791 {
792   struct GraphicInfo *g = &graphic_info[graphic];
793
794   if (g->bitmap == NULL)
795     return;
796
797   DrawBackground(x, y, width, height);
798 }
799
800 void ClearField()
801 {
802   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
803   /* (when entering hall of fame after playing) */
804   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
805
806   /* !!! maybe this should be done before clearing the background !!! */
807   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
808   {
809     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
810     SetDrawtoField(DRAW_BUFFERED);
811   }
812   else
813     SetDrawtoField(DRAW_BACKBUFFER);
814 }
815
816 void MarkTileDirty(int x, int y)
817 {
818   int xx = redraw_x1 + x;
819   int yy = redraw_y1 + y;
820
821   if (!redraw[xx][yy])
822     redraw_tiles++;
823
824   redraw[xx][yy] = TRUE;
825   redraw_mask |= REDRAW_TILES;
826 }
827
828 void SetBorderElement()
829 {
830   int x, y;
831
832   BorderElement = EL_EMPTY;
833
834   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
835   {
836     for (x = 0; x < lev_fieldx; x++)
837     {
838       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
839         BorderElement = EL_STEELWALL;
840
841       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
842         x = lev_fieldx - 2;
843     }
844   }
845 }
846
847 void FloodFillLevel(int from_x, int from_y, int fill_element,
848                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
849                     int max_fieldx, int max_fieldy)
850 {
851   int i,x,y;
852   int old_element;
853   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
854   static int safety = 0;
855
856   /* check if starting field still has the desired content */
857   if (field[from_x][from_y] == fill_element)
858     return;
859
860   safety++;
861
862   if (safety > max_fieldx * max_fieldy)
863     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
864
865   old_element = field[from_x][from_y];
866   field[from_x][from_y] = fill_element;
867
868   for (i = 0; i < 4; i++)
869   {
870     x = from_x + check[i][0];
871     y = from_y + check[i][1];
872
873     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
874       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
875   }
876
877   safety--;
878 }
879
880 void SetRandomAnimationValue(int x, int y)
881 {
882   gfx.anim_random_frame = GfxRandom[x][y];
883 }
884
885 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
886 {
887   /* animation synchronized with global frame counter, not move position */
888   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
889     sync_frame = FrameCounter;
890
891   return getAnimationFrame(graphic_info[graphic].anim_frames,
892                            graphic_info[graphic].anim_delay,
893                            graphic_info[graphic].anim_mode,
894                            graphic_info[graphic].anim_start_frame,
895                            sync_frame);
896 }
897
898 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
899                            Bitmap **bitmap, int *x, int *y)
900 {
901   struct
902   {
903     int width_mult, width_div;
904     int height_mult, height_div;
905   }
906   offset_calc[6] =
907   {
908     { 15, 16,   2, 3    },      /* 1 x 1 */
909     { 7, 8,     2, 3    },      /* 2 x 2 */
910     { 3, 4,     2, 3    },      /* 4 x 4 */
911     { 1, 2,     2, 3    },      /* 8 x 8 */
912     { 0, 1,     2, 3    },      /* 16 x 16 */
913     { 0, 1,     0, 1    },      /* 32 x 32 */
914   };
915   struct GraphicInfo *g = &graphic_info[graphic];
916   Bitmap *src_bitmap = g->bitmap;
917   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
918   int offset_calc_pos = log_2(tilesize);
919   int width_mult  = offset_calc[offset_calc_pos].width_mult;
920   int width_div   = offset_calc[offset_calc_pos].width_div;
921   int height_mult = offset_calc[offset_calc_pos].height_mult;
922   int height_div  = offset_calc[offset_calc_pos].height_div;
923   int startx = src_bitmap->width * width_mult / width_div;
924   int starty = src_bitmap->height * height_mult / height_div;
925   int src_x = g->src_x * tilesize / TILESIZE;
926   int src_y = g->src_y * tilesize / TILESIZE;
927   int width = g->width * tilesize / TILESIZE;
928   int height = g->height * tilesize / TILESIZE;
929   int offset_x = g->offset_x * tilesize / TILESIZE;
930   int offset_y = g->offset_y * tilesize / TILESIZE;
931
932   if (g->offset_y == 0)         /* frames are ordered horizontally */
933   {
934     int max_width = g->anim_frames_per_line * width;
935     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
936
937     src_x = pos % max_width;
938     src_y = src_y % height + pos / max_width * height;
939   }
940   else if (g->offset_x == 0)    /* frames are ordered vertically */
941   {
942     int max_height = g->anim_frames_per_line * height;
943     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
944
945     src_x = src_x % width + pos / max_height * width;
946     src_y = pos % max_height;
947   }
948   else                          /* frames are ordered diagonally */
949   {
950     src_x = src_x + frame * offset_x;
951     src_y = src_y + frame * offset_y;
952   }
953
954   *bitmap = src_bitmap;
955   *x = startx + src_x;
956   *y = starty + src_y;
957 }
958
959 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
960 {
961 #if 1
962   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
963 #else
964   struct GraphicInfo *g = &graphic_info[graphic];
965   int mini_startx = 0;
966   int mini_starty = g->bitmap->height * 2 / 3;
967
968   *bitmap = g->bitmap;
969   *x = mini_startx + g->src_x / 2;
970   *y = mini_starty + g->src_y / 2;
971 #endif
972 }
973
974 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
975                                 int *x, int *y, boolean get_backside)
976 {
977   struct GraphicInfo *g = &graphic_info[graphic];
978   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
979   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
980
981   *bitmap = g->bitmap;
982
983   if (g->offset_y == 0)         /* frames are ordered horizontally */
984   {
985     int max_width = g->anim_frames_per_line * g->width;
986     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
987
988     *x = pos % max_width;
989     *y = src_y % g->height + pos / max_width * g->height;
990   }
991   else if (g->offset_x == 0)    /* frames are ordered vertically */
992   {
993     int max_height = g->anim_frames_per_line * g->height;
994     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
995
996     *x = src_x % g->width + pos / max_height * g->width;
997     *y = pos % max_height;
998   }
999   else                          /* frames are ordered diagonally */
1000   {
1001     *x = src_x + frame * g->offset_x;
1002     *y = src_y + frame * g->offset_y;
1003   }
1004 }
1005
1006 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1007 {
1008   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1009 }
1010
1011 void DrawGraphic(int x, int y, int graphic, int frame)
1012 {
1013 #if DEBUG
1014   if (!IN_SCR_FIELD(x, y))
1015   {
1016     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1017     printf("DrawGraphic(): This should never happen!\n");
1018     return;
1019   }
1020 #endif
1021
1022   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1023   MarkTileDirty(x, y);
1024 }
1025
1026 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1027                     int frame)
1028 {
1029   Bitmap *src_bitmap;
1030   int src_x, src_y;
1031
1032   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1033   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1034 }
1035
1036 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1037 {
1038 #if DEBUG
1039   if (!IN_SCR_FIELD(x, y))
1040   {
1041     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1042     printf("DrawGraphicThruMask(): This should never happen!\n");
1043     return;
1044   }
1045 #endif
1046
1047   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
1048                          frame);
1049   MarkTileDirty(x, y);
1050 }
1051
1052 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1053                             int frame)
1054 {
1055   Bitmap *src_bitmap;
1056   int src_x, src_y;
1057
1058   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1059
1060   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1061                 dst_x - src_x, dst_y - src_y);
1062   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1063 }
1064
1065 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1066 {
1067   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1068                       frame, tilesize);
1069   MarkTileDirty(x / tilesize, y / tilesize);
1070 }
1071
1072 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1073                          int tilesize)
1074 {
1075   Bitmap *src_bitmap;
1076   int src_x, src_y;
1077
1078   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1079   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1080 }
1081
1082 void DrawMiniGraphic(int x, int y, int graphic)
1083 {
1084   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1085   MarkTileDirty(x / 2, y / 2);
1086 }
1087
1088 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1089 {
1090   Bitmap *src_bitmap;
1091   int src_x, src_y;
1092
1093   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1094   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1095 }
1096
1097 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1098                                             int graphic, int frame,
1099                                             int cut_mode, int mask_mode)
1100 {
1101   Bitmap *src_bitmap;
1102   int src_x, src_y;
1103   int dst_x, dst_y;
1104   int width = TILEX, height = TILEY;
1105   int cx = 0, cy = 0;
1106
1107   if (dx || dy)                 /* shifted graphic */
1108   {
1109     if (x < BX1)                /* object enters playfield from the left */
1110     {
1111       x = BX1;
1112       width = dx;
1113       cx = TILEX - dx;
1114       dx = 0;
1115     }
1116     else if (x > BX2)           /* object enters playfield from the right */
1117     {
1118       x = BX2;
1119       width = -dx;
1120       dx = TILEX + dx;
1121     }
1122     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1123     {
1124       width += dx;
1125       cx = -dx;
1126       dx = 0;
1127     }
1128     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1129       width -= dx;
1130     else if (dx)                /* general horizontal movement */
1131       MarkTileDirty(x + SIGN(dx), y);
1132
1133     if (y < BY1)                /* object enters playfield from the top */
1134     {
1135       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1136         return;
1137
1138       y = BY1;
1139       height = dy;
1140       cy = TILEY - dy;
1141       dy = 0;
1142     }
1143     else if (y > BY2)           /* object enters playfield from the bottom */
1144     {
1145       y = BY2;
1146       height = -dy;
1147       dy = TILEY + dy;
1148     }
1149     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1150     {
1151       height += dy;
1152       cy = -dy;
1153       dy = 0;
1154     }
1155     else if (dy > 0 && cut_mode == CUT_ABOVE)
1156     {
1157       if (y == BY2)             /* object completely above bottom border */
1158         return;
1159
1160       height = dy;
1161       cy = TILEY - dy;
1162       dy = TILEY;
1163       MarkTileDirty(x, y + 1);
1164     }                           /* object leaves playfield to the bottom */
1165     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1166       height -= dy;
1167     else if (dy)                /* general vertical movement */
1168       MarkTileDirty(x, y + SIGN(dy));
1169   }
1170
1171 #if DEBUG
1172   if (!IN_SCR_FIELD(x, y))
1173   {
1174     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1175     printf("DrawGraphicShifted(): This should never happen!\n");
1176     return;
1177   }
1178 #endif
1179
1180   if (width > 0 && height > 0)
1181   {
1182     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1183
1184     src_x += cx;
1185     src_y += cy;
1186
1187     dst_x = FX + x * TILEX + dx;
1188     dst_y = FY + y * TILEY + dy;
1189
1190     if (mask_mode == USE_MASKING)
1191     {
1192       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1193                     dst_x - src_x, dst_y - src_y);
1194       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1195                        dst_x, dst_y);
1196     }
1197     else
1198       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1199                  dst_x, dst_y);
1200
1201     MarkTileDirty(x, y);
1202   }
1203 }
1204
1205 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1206                                             int graphic, int frame,
1207                                             int cut_mode, int mask_mode)
1208 {
1209   Bitmap *src_bitmap;
1210   int src_x, src_y;
1211   int dst_x, dst_y;
1212   int width = TILEX, height = TILEY;
1213   int x1 = x;
1214   int y1 = y;
1215   int x2 = x + SIGN(dx);
1216   int y2 = y + SIGN(dy);
1217   int anim_frames = graphic_info[graphic].anim_frames;
1218   int sync_frame = (dx ? ABS(dx) : ABS(dy)) * anim_frames / TILESIZE;
1219   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1220   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1221
1222   /* re-calculate animation frame for two-tile movement animation */
1223   frame = getGraphicAnimationFrame(graphic, sync_frame);
1224
1225   /* check if movement start graphic inside screen area and should be drawn */
1226   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1227   {
1228     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1229
1230     dst_x = FX + x1 * TILEX;
1231     dst_y = FY + y1 * TILEY;
1232
1233     if (mask_mode == USE_MASKING)
1234     {
1235       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1236                     dst_x - src_x, dst_y - src_y);
1237       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1238                        dst_x, dst_y);
1239     }
1240     else
1241       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1242                  dst_x, dst_y);
1243
1244     MarkTileDirty(x1, y1);
1245   }
1246
1247   /* check if movement end graphic inside screen area and should be drawn */
1248   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1249   {
1250     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1251
1252     dst_x = FX + x2 * TILEX;
1253     dst_y = FY + y2 * TILEY;
1254
1255     if (mask_mode == USE_MASKING)
1256     {
1257       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1258                     dst_x - src_x, dst_y - src_y);
1259       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1260                        dst_x, dst_y);
1261     }
1262     else
1263       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1264                  dst_x, dst_y);
1265
1266     MarkTileDirty(x2, y2);
1267   }
1268 }
1269
1270 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1271                                int graphic, int frame,
1272                                int cut_mode, int mask_mode)
1273 {
1274   if (graphic < 0)
1275   {
1276     DrawGraphic(x, y, graphic, frame);
1277
1278     return;
1279   }
1280
1281   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1282     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1283   else
1284     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1285 }
1286
1287 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1288                                 int frame, int cut_mode)
1289 {
1290   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1291 }
1292
1293 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1294                           int cut_mode, int mask_mode)
1295 {
1296   int lx = LEVELX(x), ly = LEVELY(y);
1297   int graphic;
1298   int frame;
1299
1300   if (IN_LEV_FIELD(lx, ly))
1301   {
1302     SetRandomAnimationValue(lx, ly);
1303
1304     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1305     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1306
1307     /* do not use double (EM style) movement graphic when not moving */
1308     if (graphic_info[graphic].double_movement && !dx && !dy)
1309     {
1310       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1311       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1312     }
1313   }
1314   else  /* border element */
1315   {
1316     graphic = el2img(element);
1317     frame = getGraphicAnimationFrame(graphic, -1);
1318   }
1319
1320   if (element == EL_EXPANDABLE_WALL)
1321   {
1322     boolean left_stopped = FALSE, right_stopped = FALSE;
1323
1324     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1325       left_stopped = TRUE;
1326     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1327       right_stopped = TRUE;
1328
1329     if (left_stopped && right_stopped)
1330       graphic = IMG_WALL;
1331     else if (left_stopped)
1332     {
1333       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1334       frame = graphic_info[graphic].anim_frames - 1;
1335     }
1336     else if (right_stopped)
1337     {
1338       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1339       frame = graphic_info[graphic].anim_frames - 1;
1340     }
1341   }
1342
1343   if (dx || dy)
1344     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1345   else if (mask_mode == USE_MASKING)
1346     DrawGraphicThruMask(x, y, graphic, frame);
1347   else
1348     DrawGraphic(x, y, graphic, frame);
1349 }
1350
1351 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1352                          int cut_mode, int mask_mode)
1353 {
1354   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1355     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1356                          cut_mode, mask_mode);
1357 }
1358
1359 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1360                               int cut_mode)
1361 {
1362   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1363 }
1364
1365 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1366                              int cut_mode)
1367 {
1368   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1369 }
1370
1371 void DrawLevelElementThruMask(int x, int y, int element)
1372 {
1373   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1374 }
1375
1376 void DrawLevelFieldThruMask(int x, int y)
1377 {
1378   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1379 }
1380
1381 /* !!! implementation of quicksand is totally broken !!! */
1382 #define IS_CRUMBLED_TILE(x, y, e)                                       \
1383         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
1384                              !IS_MOVING(x, y) ||                        \
1385                              (e) == EL_QUICKSAND_EMPTYING ||            \
1386                              (e) == EL_QUICKSAND_FAST_EMPTYING))
1387
1388 static void DrawLevelFieldCrumbledSandExt(int x, int y, int graphic, int frame)
1389 {
1390   Bitmap *src_bitmap;
1391   int src_x, src_y;
1392   int sx = SCREENX(x), sy = SCREENY(y);
1393   int element;
1394   int width, height, cx, cy, i;
1395   int crumbled_border_size = graphic_info[graphic].border_size;
1396   static int xy[4][2] =
1397   {
1398     { 0, -1 },
1399     { -1, 0 },
1400     { +1, 0 },
1401     { 0, +1 }
1402   };
1403
1404   if (!IN_LEV_FIELD(x, y))
1405     return;
1406
1407   element = TILE_GFX_ELEMENT(x, y);
1408
1409   /* crumble field itself */
1410 #if 1
1411   if (IS_CRUMBLED_TILE(x, y, element))
1412 #else
1413   if (GFX_CRUMBLED(element) && !IS_MOVING(x, y))
1414 #endif
1415   {
1416     if (!IN_SCR_FIELD(sx, sy))
1417       return;
1418
1419     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1420
1421     for (i = 0; i < 4; i++)
1422     {
1423       int xx = x + xy[i][0];
1424       int yy = y + xy[i][1];
1425
1426       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1427                  BorderElement);
1428
1429       /* check if neighbour field is of same type */
1430 #if 1
1431       if (IS_CRUMBLED_TILE(xx, yy, element))
1432         continue;
1433 #else
1434       if (GFX_CRUMBLED(element) && !IS_MOVING(xx, yy))
1435         continue;
1436 #endif
1437
1438       if (i == 1 || i == 2)
1439       {
1440         width = crumbled_border_size;
1441         height = TILEY;
1442         cx = (i == 2 ? TILEX - crumbled_border_size : 0);
1443         cy = 0;
1444       }
1445       else
1446       {
1447         width = TILEX;
1448         height = crumbled_border_size;
1449         cx = 0;
1450         cy = (i == 3 ? TILEY - crumbled_border_size : 0);
1451       }
1452
1453       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1454                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1455     }
1456
1457     MarkTileDirty(sx, sy);
1458   }
1459   else          /* crumble neighbour fields */
1460   {
1461     for (i = 0; i < 4; i++)
1462     {
1463       int xx = x + xy[i][0];
1464       int yy = y + xy[i][1];
1465       int sxx = sx + xy[i][0];
1466       int syy = sy + xy[i][1];
1467
1468 #if 1
1469       if (!IN_LEV_FIELD(xx, yy) ||
1470           !IN_SCR_FIELD(sxx, syy))
1471         continue;
1472 #else
1473       if (!IN_LEV_FIELD(xx, yy) ||
1474           !IN_SCR_FIELD(sxx, syy) ||
1475           IS_MOVING(xx, yy))
1476         continue;
1477 #endif
1478
1479       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1480         continue;
1481
1482       element = TILE_GFX_ELEMENT(xx, yy);
1483
1484 #if 1
1485       if (!IS_CRUMBLED_TILE(xx, yy, element))
1486         continue;
1487 #else
1488       if (!GFX_CRUMBLED(element))
1489         continue;
1490 #endif
1491
1492       graphic = el_act2crm(element, ACTION_DEFAULT);
1493       crumbled_border_size = graphic_info[graphic].border_size;
1494
1495       getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1496
1497       if (i == 1 || i == 2)
1498       {
1499         width = crumbled_border_size;
1500         height = TILEY;
1501         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
1502         cy = 0;
1503       }
1504       else
1505       {
1506         width = TILEX;
1507         height = crumbled_border_size;
1508         cx = 0;
1509         cy = (i == 0 ? TILEY - crumbled_border_size : 0);
1510       }
1511
1512       BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1513                  width, height, FX + sxx * TILEX + cx, FY + syy * TILEY + cy);
1514
1515       MarkTileDirty(sxx, syy);
1516     }
1517   }
1518 }
1519
1520 void DrawLevelFieldCrumbledSand(int x, int y)
1521 {
1522   int graphic;
1523
1524   if (!IN_LEV_FIELD(x, y))
1525     return;
1526
1527 #if 1
1528   /* !!! CHECK THIS !!! */
1529
1530   /*
1531   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1532       GFX_CRUMBLED(GfxElement[x][y]))
1533   */
1534
1535   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1536       GfxElement[x][y] != EL_UNDEFINED &&
1537       GFX_CRUMBLED(GfxElement[x][y]))
1538   {
1539     DrawLevelFieldCrumbledSandDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1540
1541     return;
1542   }
1543 #endif
1544
1545 #if 1
1546   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1547 #else
1548   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
1549 #endif
1550
1551   DrawLevelFieldCrumbledSandExt(x, y, graphic, 0);
1552 }
1553
1554 void DrawLevelFieldCrumbledSandDigging(int x, int y, int direction,
1555                                        int step_frame)
1556 {
1557   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1558   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1559   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1560   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1561   int sx = SCREENX(x), sy = SCREENY(y);
1562
1563   DrawGraphic(sx, sy, graphic1, frame1);
1564   DrawLevelFieldCrumbledSandExt(x, y, graphic2, frame2);
1565 }
1566
1567 void DrawLevelFieldCrumbledSandNeighbours(int x, int y)
1568 {
1569   int sx = SCREENX(x), sy = SCREENY(y);
1570   static int xy[4][2] =
1571   {
1572     { 0, -1 },
1573     { -1, 0 },
1574     { +1, 0 },
1575     { 0, +1 }
1576   };
1577   int i;
1578
1579   for (i = 0; i < 4; i++)
1580   {
1581     int xx = x + xy[i][0];
1582     int yy = y + xy[i][1];
1583     int sxx = sx + xy[i][0];
1584     int syy = sy + xy[i][1];
1585
1586     if (!IN_LEV_FIELD(xx, yy) ||
1587         !IN_SCR_FIELD(sxx, syy) ||
1588         !GFX_CRUMBLED(Feld[xx][yy]) ||
1589         IS_MOVING(xx, yy))
1590       continue;
1591
1592     DrawLevelField(xx, yy);
1593   }
1594 }
1595
1596 static int getBorderElement(int x, int y)
1597 {
1598   int border[7][2] =
1599   {
1600     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
1601     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
1602     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1603     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1604     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
1605     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
1606     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
1607   };
1608   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1609   int steel_position = (x == -1         && y == -1              ? 0 :
1610                         x == lev_fieldx && y == -1              ? 1 :
1611                         x == -1         && y == lev_fieldy      ? 2 :
1612                         x == lev_fieldx && y == lev_fieldy      ? 3 :
1613                         x == -1         || x == lev_fieldx      ? 4 :
1614                         y == -1         || y == lev_fieldy      ? 5 : 6);
1615
1616   return border[steel_position][steel_type];
1617 }
1618
1619 void DrawScreenElement(int x, int y, int element)
1620 {
1621   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1622   DrawLevelFieldCrumbledSand(LEVELX(x), LEVELY(y));
1623 }
1624
1625 void DrawLevelElement(int x, int y, int element)
1626 {
1627   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1628     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1629 }
1630
1631 void DrawScreenField(int x, int y)
1632 {
1633   int lx = LEVELX(x), ly = LEVELY(y);
1634   int element, content;
1635
1636   if (!IN_LEV_FIELD(lx, ly))
1637   {
1638     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1639       element = EL_EMPTY;
1640     else
1641       element = getBorderElement(lx, ly);
1642
1643     DrawScreenElement(x, y, element);
1644
1645     return;
1646   }
1647
1648   element = Feld[lx][ly];
1649   content = Store[lx][ly];
1650
1651   if (IS_MOVING(lx, ly))
1652   {
1653     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1654     boolean cut_mode = NO_CUTTING;
1655
1656     if (element == EL_QUICKSAND_EMPTYING ||
1657         element == EL_QUICKSAND_FAST_EMPTYING ||
1658         element == EL_MAGIC_WALL_EMPTYING ||
1659         element == EL_BD_MAGIC_WALL_EMPTYING ||
1660         element == EL_DC_MAGIC_WALL_EMPTYING ||
1661         element == EL_AMOEBA_DROPPING)
1662       cut_mode = CUT_ABOVE;
1663     else if (element == EL_QUICKSAND_FILLING ||
1664              element == EL_QUICKSAND_FAST_FILLING ||
1665              element == EL_MAGIC_WALL_FILLING ||
1666              element == EL_BD_MAGIC_WALL_FILLING ||
1667              element == EL_DC_MAGIC_WALL_FILLING)
1668       cut_mode = CUT_BELOW;
1669
1670 #if 0
1671     if (lx == 9 && ly == 1)
1672       printf("::: %s [%d] [%d, %d] [%d]\n",
1673              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
1674              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
1675              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
1676              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
1677              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
1678 #endif
1679
1680     if (cut_mode == CUT_ABOVE)
1681 #if 1
1682       DrawScreenElement(x, y, element);
1683 #else
1684       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1685 #endif
1686     else
1687       DrawScreenElement(x, y, EL_EMPTY);
1688
1689     if (horiz_move)
1690       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1691     else if (cut_mode == NO_CUTTING)
1692       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1693     else
1694     {
1695       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1696
1697 #if 1
1698       if (cut_mode == CUT_BELOW &&
1699           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1700         DrawLevelElement(lx, ly + 1, element);
1701 #endif
1702     }
1703
1704     if (content == EL_ACID)
1705     {
1706       int dir = MovDir[lx][ly];
1707       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1708       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
1709
1710       DrawLevelElementThruMask(newlx, newly, EL_ACID);
1711     }
1712   }
1713   else if (IS_BLOCKED(lx, ly))
1714   {
1715     int oldx, oldy;
1716     int sx, sy;
1717     int horiz_move;
1718     boolean cut_mode = NO_CUTTING;
1719     int element_old, content_old;
1720
1721     Blocked2Moving(lx, ly, &oldx, &oldy);
1722     sx = SCREENX(oldx);
1723     sy = SCREENY(oldy);
1724     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1725                   MovDir[oldx][oldy] == MV_RIGHT);
1726
1727     element_old = Feld[oldx][oldy];
1728     content_old = Store[oldx][oldy];
1729
1730     if (element_old == EL_QUICKSAND_EMPTYING ||
1731         element_old == EL_QUICKSAND_FAST_EMPTYING ||
1732         element_old == EL_MAGIC_WALL_EMPTYING ||
1733         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1734         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1735         element_old == EL_AMOEBA_DROPPING)
1736       cut_mode = CUT_ABOVE;
1737
1738     DrawScreenElement(x, y, EL_EMPTY);
1739
1740     if (horiz_move)
1741       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1742                                NO_CUTTING);
1743     else if (cut_mode == NO_CUTTING)
1744       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1745                                cut_mode);
1746     else
1747       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1748                                cut_mode);
1749   }
1750   else if (IS_DRAWABLE(element))
1751     DrawScreenElement(x, y, element);
1752   else
1753     DrawScreenElement(x, y, EL_EMPTY);
1754 }
1755
1756 void DrawLevelField(int x, int y)
1757 {
1758   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1759     DrawScreenField(SCREENX(x), SCREENY(y));
1760   else if (IS_MOVING(x, y))
1761   {
1762     int newx,newy;
1763
1764     Moving2Blocked(x, y, &newx, &newy);
1765     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1766       DrawScreenField(SCREENX(newx), SCREENY(newy));
1767   }
1768   else if (IS_BLOCKED(x, y))
1769   {
1770     int oldx, oldy;
1771
1772     Blocked2Moving(x, y, &oldx, &oldy);
1773     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1774       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1775   }
1776 }
1777
1778 void DrawMiniElement(int x, int y, int element)
1779 {
1780   int graphic;
1781
1782   graphic = el2edimg(element);
1783   DrawMiniGraphic(x, y, graphic);
1784 }
1785
1786 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1787 {
1788   int x = sx + scroll_x, y = sy + scroll_y;
1789
1790   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1791     DrawMiniElement(sx, sy, EL_EMPTY);
1792   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1793     DrawMiniElement(sx, sy, Feld[x][y]);
1794   else
1795     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1796 }
1797
1798 void DrawEnvelopeBackground(int envelope_nr, int startx, int starty,
1799                             int x, int y, int xsize, int ysize, int font_nr)
1800 {
1801   int font_width  = getFontWidth(font_nr);
1802   int font_height = getFontHeight(font_nr);
1803   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1804   Bitmap *src_bitmap;
1805   int src_x, src_y;
1806   int dst_x = SX + startx + x * font_width;
1807   int dst_y = SY + starty + y * font_height;
1808   int width  = graphic_info[graphic].width;
1809   int height = graphic_info[graphic].height;
1810   int inner_width  = MAX(width  - 2 * font_width,  font_width);
1811   int inner_height = MAX(height - 2 * font_height, font_height);
1812   int inner_sx = (width >= 3 * font_width ? font_width : 0);
1813   int inner_sy = (height >= 3 * font_height ? font_height : 0);
1814   boolean draw_masked = graphic_info[graphic].draw_masked;
1815
1816   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1817
1818   if (src_bitmap == NULL || width < font_width || height < font_height)
1819   {
1820     ClearRectangle(drawto, dst_x, dst_y, font_width, font_height);
1821     return;
1822   }
1823
1824   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - font_width  :
1825             inner_sx + (x - 1) * font_width  % inner_width);
1826   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - font_height :
1827             inner_sy + (y - 1) * font_height % inner_height);
1828
1829   if (draw_masked)
1830   {
1831     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1832                   dst_x - src_x, dst_y - src_y);
1833     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1834                      dst_x, dst_y);
1835   }
1836   else
1837     BlitBitmap(src_bitmap, drawto, src_x, src_y, font_width, font_height,
1838                dst_x, dst_y);
1839 }
1840
1841 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
1842 {
1843   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1844   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1845   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
1846   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1847   boolean no_delay = (tape.warp_forward);
1848   unsigned long anim_delay = 0;
1849   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
1850   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
1851   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
1852   int font_width = getFontWidth(font_nr);
1853   int font_height = getFontHeight(font_nr);
1854   int max_xsize = level.envelope[envelope_nr].xsize;
1855   int max_ysize = level.envelope[envelope_nr].ysize;
1856   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
1857   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
1858   int xend = max_xsize;
1859   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
1860   int xstep = (xstart < xend ? 1 : 0);
1861   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
1862   int x, y;
1863
1864   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
1865   {
1866     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
1867     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
1868     int sx = (SXSIZE - xsize * font_width)  / 2;
1869     int sy = (SYSIZE - ysize * font_height) / 2;
1870     int xx, yy;
1871
1872     SetDrawtoField(DRAW_BUFFERED);
1873
1874     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
1875
1876     SetDrawtoField(DRAW_BACKBUFFER);
1877
1878     for (yy = 0; yy < ysize; yy++) for (xx = 0; xx < xsize; xx++)
1879       DrawEnvelopeBackground(envelope_nr, sx,sy, xx,yy, xsize, ysize, font_nr);
1880
1881 #if 1
1882     DrawTextBuffer(SX + sx + font_width, SY + sy + font_height,
1883                    level.envelope[envelope_nr].text, font_nr, max_xsize,
1884                    xsize - 2, ysize - 2, mask_mode,
1885                    level.envelope[envelope_nr].autowrap,
1886                    level.envelope[envelope_nr].centered, FALSE);
1887 #else
1888     DrawTextToTextArea(SX + sx + font_width, SY + sy + font_height,
1889                        level.envelope[envelope_nr].text, font_nr, max_xsize,
1890                        xsize - 2, ysize - 2, mask_mode);
1891 #endif
1892
1893     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
1894     BackToFront();
1895
1896     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
1897   }
1898 }
1899
1900 void ShowEnvelope(int envelope_nr)
1901 {
1902   int element = EL_ENVELOPE_1 + envelope_nr;
1903   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
1904   int sound_opening = element_info[element].sound[ACTION_OPENING];
1905   int sound_closing = element_info[element].sound[ACTION_CLOSING];
1906   boolean ffwd_delay = (tape.playing && tape.fast_forward);
1907   boolean no_delay = (tape.warp_forward);
1908   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
1909   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
1910   int anim_mode = graphic_info[graphic].anim_mode;
1911   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
1912                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
1913
1914   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
1915
1916   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
1917
1918   if (anim_mode == ANIM_DEFAULT)
1919     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
1920
1921   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
1922
1923   if (tape.playing)
1924     Delay(wait_delay_value);
1925   else
1926     WaitForEventToContinue();
1927
1928   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
1929
1930   if (anim_mode != ANIM_NONE)
1931     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
1932
1933   if (anim_mode == ANIM_DEFAULT)
1934     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
1935
1936   game.envelope_active = FALSE;
1937
1938   SetDrawtoField(DRAW_BUFFERED);
1939
1940   redraw_mask |= REDRAW_FIELD;
1941   BackToFront();
1942 }
1943
1944 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
1945 {
1946   Bitmap *src_bitmap;
1947   int src_x, src_y;
1948   int graphic = el2preimg(element);
1949
1950   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
1951   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
1952 }
1953
1954 void DrawLevel()
1955 {
1956   int x,y;
1957
1958 #if 1
1959   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
1960   SetDrawBackgroundMask(REDRAW_FIELD);
1961 #else
1962   SetDrawBackgroundMask(REDRAW_NONE);
1963 #endif
1964
1965   ClearField();
1966
1967   for (x = BX1; x <= BX2; x++)
1968     for (y = BY1; y <= BY2; y++)
1969       DrawScreenField(x, y);
1970
1971   redraw_mask |= REDRAW_FIELD;
1972 }
1973
1974 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1975 {
1976   int x,y;
1977
1978   for (x = 0; x < size_x; x++)
1979     for (y = 0; y < size_y; y++)
1980       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1981
1982   redraw_mask |= REDRAW_FIELD;
1983 }
1984
1985 static void DrawPreviewLevelExt(int from_x, int from_y)
1986 {
1987   boolean show_level_border = (BorderElement != EL_EMPTY);
1988   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
1989   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
1990   int tile_size = preview.tile_size;
1991   int preview_width  = preview.xsize * tile_size;
1992   int preview_height = preview.ysize * tile_size;
1993   int real_preview_xsize = MIN(level_xsize, preview.xsize);
1994   int real_preview_ysize = MIN(level_ysize, preview.ysize);
1995   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
1996   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
1997   int x, y;
1998
1999   DrawBackground(dst_x, dst_y, preview_width, preview_height);
2000
2001   dst_x += (preview_width  - real_preview_xsize * tile_size) / 2;
2002   dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
2003
2004   for (x = 0; x < real_preview_xsize; x++)
2005   {
2006     for (y = 0; y < real_preview_ysize; y++)
2007     {
2008       int lx = from_x + x + (show_level_border ? -1 : 0);
2009       int ly = from_y + y + (show_level_border ? -1 : 0);
2010       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2011                      getBorderElement(lx, ly));
2012
2013       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2014                          element, tile_size);
2015     }
2016   }
2017
2018   redraw_mask |= REDRAW_MICROLEVEL;
2019 }
2020
2021 #define MICROLABEL_EMPTY                0
2022 #define MICROLABEL_LEVEL_NAME           1
2023 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
2024 #define MICROLABEL_LEVEL_AUTHOR         3
2025 #define MICROLABEL_IMPORTED_FROM_HEAD   4
2026 #define MICROLABEL_IMPORTED_FROM        5
2027 #define MICROLABEL_IMPORTED_BY_HEAD     6
2028 #define MICROLABEL_IMPORTED_BY          7
2029
2030 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2031 {
2032   int max_text_width = SXSIZE;
2033   int font_width = getFontWidth(font_nr);
2034
2035   if (pos->align == ALIGN_CENTER)
2036     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2037   else if (pos->align == ALIGN_RIGHT)
2038     max_text_width = pos->x;
2039   else
2040     max_text_width = SXSIZE - pos->x;
2041
2042   return max_text_width / font_width;
2043 }
2044
2045 static void DrawPreviewLevelLabelExt(int mode)
2046 {
2047   struct TextPosInfo *pos = &menu.main.text.level_info_2;
2048   char label_text[MAX_OUTPUT_LINESIZE + 1];
2049   int max_len_label_text;
2050 #if 1
2051   int font_nr = pos->font;
2052   int i;
2053
2054   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2055       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2056       mode == MICROLABEL_IMPORTED_BY_HEAD)
2057     font_nr = pos->font_alt;
2058 #else
2059   int font_nr = FONT_TEXT_2;
2060   int i;
2061
2062   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2063       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2064       mode == MICROLABEL_IMPORTED_BY_HEAD)
2065     font_nr = FONT_TEXT_3;
2066 #endif
2067
2068 #if 1
2069   max_len_label_text = getMaxTextLength(pos, font_nr);
2070 #else
2071   max_len_label_text = SXSIZE / getFontWidth(font_nr);
2072 #endif
2073
2074 #if 1
2075   if (pos->size != -1)
2076     max_len_label_text = pos->size;
2077 #endif
2078
2079   for (i = 0; i < max_len_label_text; i++)
2080     label_text[i] = ' ';
2081   label_text[max_len_label_text] = '\0';
2082
2083   if (strlen(label_text) > 0)
2084   {
2085 #if 1
2086     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2087 #else
2088     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2089     int lypos = MICROLABEL2_YPOS;
2090
2091     DrawText(lxpos, lypos, label_text, font_nr);
2092 #endif
2093   }
2094
2095   strncpy(label_text,
2096           (mode == MICROLABEL_LEVEL_NAME ? level.name :
2097            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2098            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2099            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2100            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2101            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2102            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2103           max_len_label_text);
2104   label_text[max_len_label_text] = '\0';
2105
2106   if (strlen(label_text) > 0)
2107   {
2108 #if 1
2109     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2110 #else
2111     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2112     int lypos = MICROLABEL2_YPOS;
2113
2114     DrawText(lxpos, lypos, label_text, font_nr);
2115 #endif
2116   }
2117
2118   redraw_mask |= REDRAW_MICROLEVEL;
2119 }
2120
2121 void DrawPreviewLevel(boolean restart)
2122 {
2123   static unsigned long scroll_delay = 0;
2124   static unsigned long label_delay = 0;
2125   static int from_x, from_y, scroll_direction;
2126   static int label_state, label_counter;
2127   unsigned long scroll_delay_value = preview.step_delay;
2128   boolean show_level_border = (BorderElement != EL_EMPTY);
2129   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2130   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2131   int last_game_status = game_status;           /* save current game status */
2132
2133 #if 0
2134   /* force PREVIEW font on preview level */
2135   game_status = GAME_MODE_PSEUDO_PREVIEW;
2136 #endif
2137
2138   if (restart)
2139   {
2140     from_x = 0;
2141     from_y = 0;
2142
2143     if (preview.anim_mode == ANIM_CENTERED)
2144     {
2145       if (level_xsize > preview.xsize)
2146         from_x = (level_xsize - preview.xsize) / 2;
2147       if (level_ysize > preview.ysize)
2148         from_y = (level_ysize - preview.ysize) / 2;
2149     }
2150
2151     from_x += preview.xoffset;
2152     from_y += preview.yoffset;
2153
2154     scroll_direction = MV_RIGHT;
2155     label_state = 1;
2156     label_counter = 0;
2157
2158     DrawPreviewLevelExt(from_x, from_y);
2159     DrawPreviewLevelLabelExt(label_state);
2160
2161     /* initialize delay counters */
2162     DelayReached(&scroll_delay, 0);
2163     DelayReached(&label_delay, 0);
2164
2165     if (leveldir_current->name)
2166     {
2167       struct TextPosInfo *pos = &menu.main.text.level_info_1;
2168       char label_text[MAX_OUTPUT_LINESIZE + 1];
2169 #if 1
2170       int font_nr = pos->font;
2171 #else
2172       int font_nr = FONT_TEXT_1;
2173 #endif
2174 #if 1
2175       int max_len_label_text = getMaxTextLength(pos, font_nr);
2176 #else
2177       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
2178 #endif
2179 #if 0
2180       int text_width;
2181       int lxpos, lypos;
2182 #endif
2183
2184 #if 1
2185       if (pos->size != -1)
2186         max_len_label_text = pos->size;
2187 #endif
2188
2189       strncpy(label_text, leveldir_current->name, max_len_label_text);
2190       label_text[max_len_label_text] = '\0';
2191
2192 #if 1
2193       DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2194 #else
2195       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
2196       lypos = SY + MICROLABEL1_YPOS;
2197
2198       DrawText(lxpos, lypos, label_text, font_nr);
2199 #endif
2200     }
2201
2202     game_status = last_game_status;     /* restore current game status */
2203
2204     return;
2205   }
2206
2207   /* scroll preview level, if needed */
2208   if (preview.anim_mode != ANIM_NONE &&
2209       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2210       DelayReached(&scroll_delay, scroll_delay_value))
2211   {
2212     switch (scroll_direction)
2213     {
2214       case MV_LEFT:
2215         if (from_x > 0)
2216         {
2217           from_x -= preview.step_offset;
2218           from_x = (from_x < 0 ? 0 : from_x);
2219         }
2220         else
2221           scroll_direction = MV_UP;
2222         break;
2223
2224       case MV_RIGHT:
2225         if (from_x < level_xsize - preview.xsize)
2226         {
2227           from_x += preview.step_offset;
2228           from_x = (from_x > level_xsize - preview.xsize ?
2229                     level_xsize - preview.xsize : from_x);
2230         }
2231         else
2232           scroll_direction = MV_DOWN;
2233         break;
2234
2235       case MV_UP:
2236         if (from_y > 0)
2237         {
2238           from_y -= preview.step_offset;
2239           from_y = (from_y < 0 ? 0 : from_y);
2240         }
2241         else
2242           scroll_direction = MV_RIGHT;
2243         break;
2244
2245       case MV_DOWN:
2246         if (from_y < level_ysize - preview.ysize)
2247         {
2248           from_y += preview.step_offset;
2249           from_y = (from_y > level_ysize - preview.ysize ?
2250                     level_ysize - preview.ysize : from_y);
2251         }
2252         else
2253           scroll_direction = MV_LEFT;
2254         break;
2255
2256       default:
2257         break;
2258     }
2259
2260     DrawPreviewLevelExt(from_x, from_y);
2261   }
2262
2263   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2264   /* redraw micro level label, if needed */
2265   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2266       !strEqual(level.author, ANONYMOUS_NAME) &&
2267       !strEqual(level.author, leveldir_current->name) &&
2268       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2269   {
2270     int max_label_counter = 23;
2271
2272     if (leveldir_current->imported_from != NULL &&
2273         strlen(leveldir_current->imported_from) > 0)
2274       max_label_counter += 14;
2275     if (leveldir_current->imported_by != NULL &&
2276         strlen(leveldir_current->imported_by) > 0)
2277       max_label_counter += 14;
2278
2279     label_counter = (label_counter + 1) % max_label_counter;
2280     label_state = (label_counter >= 0 && label_counter <= 7 ?
2281                    MICROLABEL_LEVEL_NAME :
2282                    label_counter >= 9 && label_counter <= 12 ?
2283                    MICROLABEL_LEVEL_AUTHOR_HEAD :
2284                    label_counter >= 14 && label_counter <= 21 ?
2285                    MICROLABEL_LEVEL_AUTHOR :
2286                    label_counter >= 23 && label_counter <= 26 ?
2287                    MICROLABEL_IMPORTED_FROM_HEAD :
2288                    label_counter >= 28 && label_counter <= 35 ?
2289                    MICROLABEL_IMPORTED_FROM :
2290                    label_counter >= 37 && label_counter <= 40 ?
2291                    MICROLABEL_IMPORTED_BY_HEAD :
2292                    label_counter >= 42 && label_counter <= 49 ?
2293                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2294
2295     if (leveldir_current->imported_from == NULL &&
2296         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2297          label_state == MICROLABEL_IMPORTED_FROM))
2298       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2299                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2300
2301     DrawPreviewLevelLabelExt(label_state);
2302   }
2303
2304   game_status = last_game_status;       /* restore current game status */
2305 }
2306
2307 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2308                                     int graphic, int sync_frame, int mask_mode)
2309 {
2310   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2311
2312   if (mask_mode == USE_MASKING)
2313     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2314   else
2315     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2316 }
2317
2318 inline void DrawGraphicAnimation(int x, int y, int graphic)
2319 {
2320   int lx = LEVELX(x), ly = LEVELY(y);
2321
2322   if (!IN_SCR_FIELD(x, y))
2323     return;
2324
2325   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2326                           graphic, GfxFrame[lx][ly], NO_MASKING);
2327   MarkTileDirty(x, y);
2328 }
2329
2330 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2331 {
2332   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2333 }
2334
2335 void DrawLevelElementAnimation(int x, int y, int element)
2336 {
2337   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2338
2339   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2340 }
2341
2342 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2343 {
2344   int sx = SCREENX(x), sy = SCREENY(y);
2345
2346   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2347     return;
2348
2349   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2350     return;
2351
2352   DrawGraphicAnimation(sx, sy, graphic);
2353
2354 #if 1
2355   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2356     DrawLevelFieldCrumbledSand(x, y);
2357 #else
2358   if (GFX_CRUMBLED(Feld[x][y]))
2359     DrawLevelFieldCrumbledSand(x, y);
2360 #endif
2361 }
2362
2363 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2364 {
2365   int sx = SCREENX(x), sy = SCREENY(y);
2366   int graphic;
2367
2368   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2369     return;
2370
2371   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2372
2373   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2374     return;
2375
2376   DrawGraphicAnimation(sx, sy, graphic);
2377
2378   if (GFX_CRUMBLED(element))
2379     DrawLevelFieldCrumbledSand(x, y);
2380 }
2381
2382 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2383 {
2384   if (player->use_murphy)
2385   {
2386     /* this works only because currently only one player can be "murphy" ... */
2387     static int last_horizontal_dir = MV_LEFT;
2388     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2389
2390     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2391       last_horizontal_dir = move_dir;
2392
2393     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
2394     {
2395       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2396
2397       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2398     }
2399
2400     return graphic;
2401   }
2402   else
2403     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2404 }
2405
2406 static boolean equalGraphics(int graphic1, int graphic2)
2407 {
2408   struct GraphicInfo *g1 = &graphic_info[graphic1];
2409   struct GraphicInfo *g2 = &graphic_info[graphic2];
2410
2411   return (g1->bitmap      == g2->bitmap &&
2412           g1->src_x       == g2->src_x &&
2413           g1->src_y       == g2->src_y &&
2414           g1->anim_frames == g2->anim_frames &&
2415           g1->anim_delay  == g2->anim_delay &&
2416           g1->anim_mode   == g2->anim_mode);
2417 }
2418
2419 void DrawAllPlayers()
2420 {
2421   int i;
2422
2423   for (i = 0; i < MAX_PLAYERS; i++)
2424     if (stored_player[i].active)
2425       DrawPlayer(&stored_player[i]);
2426 }
2427
2428 void DrawPlayerField(int x, int y)
2429 {
2430   if (!IS_PLAYER(x, y))
2431     return;
2432
2433   DrawPlayer(PLAYERINFO(x, y));
2434 }
2435
2436 void DrawPlayer(struct PlayerInfo *player)
2437 {
2438   int jx = player->jx;
2439   int jy = player->jy;
2440   int move_dir = player->MovDir;
2441   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2442   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
2443   int last_jx = (player->is_moving ? jx - dx : jx);
2444   int last_jy = (player->is_moving ? jy - dy : jy);
2445   int next_jx = jx + dx;
2446   int next_jy = jy + dy;
2447   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2448   boolean player_is_opaque = FALSE;
2449   int sx = SCREENX(jx), sy = SCREENY(jy);
2450   int sxx = 0, syy = 0;
2451   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2452   int graphic;
2453   int action = ACTION_DEFAULT;
2454   int last_player_graphic = getPlayerGraphic(player, move_dir);
2455   int last_player_frame = player->Frame;
2456   int frame = 0;
2457
2458   /* GfxElement[][] is set to the element the player is digging or collecting;
2459      remove also for off-screen player if the player is not moving anymore */
2460   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2461     GfxElement[jx][jy] = EL_UNDEFINED;
2462
2463   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2464     return;
2465
2466 #if DEBUG
2467   if (!IN_LEV_FIELD(jx, jy))
2468   {
2469     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2470     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2471     printf("DrawPlayerField(): This should never happen!\n");
2472     return;
2473   }
2474 #endif
2475
2476   if (element == EL_EXPLOSION)
2477     return;
2478
2479   action = (player->is_pushing    ? ACTION_PUSHING         :
2480             player->is_digging    ? ACTION_DIGGING         :
2481             player->is_collecting ? ACTION_COLLECTING      :
2482             player->is_moving     ? ACTION_MOVING          :
2483             player->is_snapping   ? ACTION_SNAPPING        :
2484             player->is_dropping   ? ACTION_DROPPING        :
2485             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
2486
2487   if (player->is_waiting)
2488     move_dir = player->dir_waiting;
2489
2490   InitPlayerGfxAnimation(player, action, move_dir);
2491
2492   /* ----------------------------------------------------------------------- */
2493   /* draw things in the field the player is leaving, if needed               */
2494   /* ----------------------------------------------------------------------- */
2495
2496   if (player->is_moving)
2497   {
2498     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2499     {
2500       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2501
2502       if (last_element == EL_DYNAMITE_ACTIVE ||
2503           last_element == EL_EM_DYNAMITE_ACTIVE ||
2504           last_element == EL_SP_DISK_RED_ACTIVE)
2505         DrawDynamite(last_jx, last_jy);
2506       else
2507         DrawLevelFieldThruMask(last_jx, last_jy);
2508     }
2509     else if (last_element == EL_DYNAMITE_ACTIVE ||
2510              last_element == EL_EM_DYNAMITE_ACTIVE ||
2511              last_element == EL_SP_DISK_RED_ACTIVE)
2512       DrawDynamite(last_jx, last_jy);
2513 #if 0
2514     /* !!! this is not enough to prevent flickering of players which are
2515        moving next to each others without a free tile between them -- this
2516        can only be solved by drawing all players layer by layer (first the
2517        background, then the foreground etc.) !!! => TODO */
2518     else if (!IS_PLAYER(last_jx, last_jy))
2519       DrawLevelField(last_jx, last_jy);
2520 #else
2521     else
2522       DrawLevelField(last_jx, last_jy);
2523 #endif
2524
2525     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2526       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2527   }
2528
2529   if (!IN_SCR_FIELD(sx, sy))
2530     return;
2531
2532   /* ----------------------------------------------------------------------- */
2533   /* draw things behind the player, if needed                                */
2534   /* ----------------------------------------------------------------------- */
2535
2536   if (Back[jx][jy])
2537     DrawLevelElement(jx, jy, Back[jx][jy]);
2538   else if (IS_ACTIVE_BOMB(element))
2539     DrawLevelElement(jx, jy, EL_EMPTY);
2540   else
2541   {
2542     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
2543     {
2544       int old_element = GfxElement[jx][jy];
2545       int old_graphic = el_act_dir2img(old_element, action, move_dir);
2546       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
2547
2548       if (GFX_CRUMBLED(old_element))
2549         DrawLevelFieldCrumbledSandDigging(jx, jy, move_dir, player->StepFrame);
2550       else
2551         DrawGraphic(sx, sy, old_graphic, frame);
2552
2553       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
2554         player_is_opaque = TRUE;
2555     }
2556     else
2557     {
2558       GfxElement[jx][jy] = EL_UNDEFINED;
2559
2560       /* make sure that pushed elements are drawn with correct frame rate */
2561 #if 1
2562       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2563
2564       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
2565         GfxFrame[jx][jy] = player->StepFrame;
2566 #else
2567       if (player->is_pushing && player->is_moving)
2568         GfxFrame[jx][jy] = player->StepFrame;
2569 #endif
2570
2571       DrawLevelField(jx, jy);
2572     }
2573   }
2574
2575   /* ----------------------------------------------------------------------- */
2576   /* draw player himself                                                     */
2577   /* ----------------------------------------------------------------------- */
2578
2579   graphic = getPlayerGraphic(player, move_dir);
2580
2581   /* in the case of changed player action or direction, prevent the current
2582      animation frame from being restarted for identical animations */
2583   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
2584     player->Frame = last_player_frame;
2585
2586   frame = getGraphicAnimationFrame(graphic, player->Frame);
2587
2588   if (player->GfxPos)
2589   {
2590     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2591       sxx = player->GfxPos;
2592     else
2593       syy = player->GfxPos;
2594   }
2595
2596   if (!setup.soft_scrolling && ScreenMovPos)
2597     sxx = syy = 0;
2598
2599   if (player_is_opaque)
2600     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
2601   else
2602     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2603
2604   if (SHIELD_ON(player))
2605   {
2606     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
2607                    IMG_SHIELD_NORMAL_ACTIVE);
2608     int frame = getGraphicAnimationFrame(graphic, -1);
2609
2610     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
2611   }
2612
2613   /* ----------------------------------------------------------------------- */
2614   /* draw things the player is pushing, if needed                            */
2615   /* ----------------------------------------------------------------------- */
2616
2617 #if 0
2618   printf("::: %d, %d [%d, %d] [%d]\n",
2619          player->is_pushing, player_is_moving, player->GfxAction,
2620          player->is_moving, player_is_moving);
2621 #endif
2622
2623 #if 1
2624   if (player->is_pushing && player->is_moving)
2625   {
2626     int px = SCREENX(jx), py = SCREENY(jy);
2627     int pxx = (TILEX - ABS(sxx)) * dx;
2628     int pyy = (TILEY - ABS(syy)) * dy;
2629     int gfx_frame = GfxFrame[jx][jy];
2630
2631     int graphic;
2632     int sync_frame;
2633     int frame;
2634
2635     if (!IS_MOVING(jx, jy))             /* push movement already finished */
2636     {
2637       element = Feld[next_jx][next_jy];
2638       gfx_frame = GfxFrame[next_jx][next_jy];
2639     }
2640
2641     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
2642
2643 #if 1
2644     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
2645     frame = getGraphicAnimationFrame(graphic, sync_frame);
2646 #else
2647     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
2648 #endif
2649
2650     /* draw background element under pushed element (like the Sokoban field) */
2651     if (Back[next_jx][next_jy])
2652       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
2653
2654     /* masked drawing is needed for EMC style (double) movement graphics */
2655     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
2656   }
2657 #endif
2658
2659   /* ----------------------------------------------------------------------- */
2660   /* draw things in front of player (active dynamite or dynabombs)           */
2661   /* ----------------------------------------------------------------------- */
2662
2663   if (IS_ACTIVE_BOMB(element))
2664   {
2665     graphic = el2img(element);
2666     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
2667
2668     if (game.emulation == EMU_SUPAPLEX)
2669       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
2670     else
2671       DrawGraphicThruMask(sx, sy, graphic, frame);
2672   }
2673
2674   if (player_is_moving && last_element == EL_EXPLOSION)
2675   {
2676     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
2677                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
2678     int graphic = el_act2img(element, ACTION_EXPLODING);
2679     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
2680     int phase = ExplodePhase[last_jx][last_jy] - 1;
2681     int frame = getGraphicAnimationFrame(graphic, phase - delay);
2682
2683     if (phase >= delay)
2684       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
2685   }
2686
2687   /* ----------------------------------------------------------------------- */
2688   /* draw elements the player is just walking/passing through/under          */
2689   /* ----------------------------------------------------------------------- */
2690
2691   if (player_is_moving)
2692   {
2693     /* handle the field the player is leaving ... */
2694     if (IS_ACCESSIBLE_INSIDE(last_element))
2695       DrawLevelField(last_jx, last_jy);
2696     else if (IS_ACCESSIBLE_UNDER(last_element))
2697       DrawLevelFieldThruMask(last_jx, last_jy);
2698   }
2699
2700   /* do not redraw accessible elements if the player is just pushing them */
2701   if (!player_is_moving || !player->is_pushing)
2702   {
2703     /* ... and the field the player is entering */
2704     if (IS_ACCESSIBLE_INSIDE(element))
2705       DrawLevelField(jx, jy);
2706     else if (IS_ACCESSIBLE_UNDER(element))
2707       DrawLevelFieldThruMask(jx, jy);
2708   }
2709
2710   MarkTileDirty(sx, sy);
2711 }
2712
2713 /* ------------------------------------------------------------------------- */
2714
2715 void WaitForEventToContinue()
2716 {
2717   boolean still_wait = TRUE;
2718
2719   /* simulate releasing mouse button over last gadget, if still pressed */
2720   if (button_status)
2721     HandleGadgets(-1, -1, 0);
2722
2723   button_status = MB_RELEASED;
2724
2725 #if 1
2726   ClearEventQueue();
2727 #endif
2728
2729   while (still_wait)
2730   {
2731     if (PendingEvent())
2732     {
2733       Event event;
2734
2735       NextEvent(&event);
2736
2737       switch (event.type)
2738       {
2739         case EVENT_BUTTONPRESS:
2740         case EVENT_KEYPRESS:
2741           still_wait = FALSE;
2742           break;
2743
2744         case EVENT_KEYRELEASE:
2745           ClearPlayerAction();
2746           break;
2747
2748         default:
2749           HandleOtherEvents(&event);
2750           break;
2751       }
2752     }
2753     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2754     {
2755       still_wait = FALSE;
2756     }
2757
2758     DoAnimation();
2759
2760     /* don't eat all CPU time */
2761     Delay(10);
2762   }
2763 }
2764
2765 #define MAX_REQUEST_LINES               13
2766 #define MAX_REQUEST_LINE_FONT1_LEN      7
2767 #define MAX_REQUEST_LINE_FONT2_LEN      10
2768
2769 boolean Request(char *text, unsigned int req_state)
2770 {
2771   int mx, my, ty, result = -1;
2772   unsigned int old_door_state;
2773   int last_game_status = game_status;   /* save current game status */
2774   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
2775   int font_nr = FONT_TEXT_2;
2776   int max_word_len = 0;
2777   char *text_ptr;
2778
2779   for (text_ptr = text; *text_ptr; text_ptr++)
2780   {
2781     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2782
2783     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
2784     {
2785       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
2786 #if 1
2787       font_nr = FONT_TEXT_1;
2788 #else
2789       font_nr = FONT_LEVEL_NUMBER;
2790 #endif
2791
2792       break;
2793     }
2794   }
2795
2796   if (game_status == GAME_MODE_PLAYING &&
2797       level.game_engine_type == GAME_ENGINE_TYPE_EM)
2798     BlitScreenToBitmap_EM(backbuffer);
2799
2800   /* disable deactivated drawing when quick-loading level tape recording */
2801   if (tape.playing && tape.deactivate_display)
2802     TapeDeactivateDisplayOff(TRUE);
2803
2804   SetMouseCursor(CURSOR_DEFAULT);
2805
2806 #if defined(NETWORK_AVALIABLE)
2807   /* pause network game while waiting for request to answer */
2808   if (options.network &&
2809       game_status == GAME_MODE_PLAYING &&
2810       req_state & REQUEST_WAIT_FOR_INPUT)
2811     SendToServer_PausePlaying();
2812 #endif
2813
2814   old_door_state = GetDoorState();
2815
2816   /* simulate releasing mouse button over last gadget, if still pressed */
2817   if (button_status)
2818     HandleGadgets(-1, -1, 0);
2819
2820   UnmapAllGadgets();
2821
2822   if (old_door_state & DOOR_OPEN_1)
2823   {
2824     CloseDoor(DOOR_CLOSE_1);
2825
2826     /* save old door content */
2827     BlitBitmap(bitmap_db_door, bitmap_db_door,
2828                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2829                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2830   }
2831
2832 #if 1
2833   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
2834 #endif
2835
2836   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2837
2838   /* clear door drawing field */
2839   DrawBackground(DX, DY, DXSIZE, DYSIZE);
2840
2841   /* force DOOR font inside door area */
2842   game_status = GAME_MODE_PSEUDO_DOOR;
2843
2844   /* write text for request */
2845   for (ty = 0; ty < MAX_REQUEST_LINES; ty++)
2846   {
2847     char text_line[max_request_line_len + 1];
2848     int tx, tl, tc = 0;
2849
2850     if (!*text)
2851       break;
2852
2853     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
2854     {
2855       tc = *(text + tx);
2856       if (!tc || tc == ' ')
2857         break;
2858     }
2859
2860     if (!tl)
2861     { 
2862       text++; 
2863       ty--; 
2864       continue; 
2865     }
2866
2867     strncpy(text_line, text, tl);
2868     text_line[tl] = 0;
2869
2870     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
2871              DY + 8 + ty * (getFontHeight(font_nr) + 2),
2872              text_line, font_nr);
2873
2874     text += tl + (tc == ' ' ? 1 : 0);
2875   }
2876
2877   game_status = last_game_status;       /* restore current game status */
2878
2879   if (req_state & REQ_ASK)
2880   {
2881     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2882     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2883   }
2884   else if (req_state & REQ_CONFIRM)
2885   {
2886     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2887   }
2888   else if (req_state & REQ_PLAYER)
2889   {
2890     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2891     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2892     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2893     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2894   }
2895
2896   /* copy request gadgets to door backbuffer */
2897   BlitBitmap(drawto, bitmap_db_door,
2898              DX, DY, DXSIZE, DYSIZE,
2899              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2900
2901   OpenDoor(DOOR_OPEN_1);
2902
2903   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
2904   {
2905     if (game_status == GAME_MODE_PLAYING)
2906     {
2907       SetPanelBackground();
2908       SetDrawBackgroundMask(REDRAW_DOOR_1);
2909     }
2910     else
2911     {
2912       SetDrawBackgroundMask(REDRAW_FIELD);
2913     }
2914
2915     return FALSE;
2916   }
2917
2918   if (game_status != GAME_MODE_MAIN)
2919     InitAnimation();
2920
2921   button_status = MB_RELEASED;
2922
2923   request_gadget_id = -1;
2924
2925   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2926
2927   while (result < 0)
2928   {
2929     if (PendingEvent())
2930     {
2931       Event event;
2932
2933       NextEvent(&event);
2934
2935       switch (event.type)
2936       {
2937         case EVENT_BUTTONPRESS:
2938         case EVENT_BUTTONRELEASE:
2939         case EVENT_MOTIONNOTIFY:
2940         {
2941           if (event.type == EVENT_MOTIONNOTIFY)
2942           {
2943             if (!PointerInWindow(window))
2944               continue; /* window and pointer are on different screens */
2945
2946             if (!button_status)
2947               continue;
2948
2949             motion_status = TRUE;
2950             mx = ((MotionEvent *) &event)->x;
2951             my = ((MotionEvent *) &event)->y;
2952           }
2953           else
2954           {
2955             motion_status = FALSE;
2956             mx = ((ButtonEvent *) &event)->x;
2957             my = ((ButtonEvent *) &event)->y;
2958             if (event.type == EVENT_BUTTONPRESS)
2959               button_status = ((ButtonEvent *) &event)->button;
2960             else
2961               button_status = MB_RELEASED;
2962           }
2963
2964           /* this sets 'request_gadget_id' */
2965           HandleGadgets(mx, my, button_status);
2966
2967           switch (request_gadget_id)
2968           {
2969             case TOOL_CTRL_ID_YES:
2970               result = TRUE;
2971               break;
2972             case TOOL_CTRL_ID_NO:
2973               result = FALSE;
2974               break;
2975             case TOOL_CTRL_ID_CONFIRM:
2976               result = TRUE | FALSE;
2977               break;
2978
2979             case TOOL_CTRL_ID_PLAYER_1:
2980               result = 1;
2981               break;
2982             case TOOL_CTRL_ID_PLAYER_2:
2983               result = 2;
2984               break;
2985             case TOOL_CTRL_ID_PLAYER_3:
2986               result = 3;
2987               break;
2988             case TOOL_CTRL_ID_PLAYER_4:
2989               result = 4;
2990               break;
2991
2992             default:
2993               break;
2994           }
2995
2996           break;
2997         }
2998
2999         case EVENT_KEYPRESS:
3000           switch (GetEventKey((KeyEvent *)&event, TRUE))
3001           {
3002             case KSYM_space:
3003               if (req_state & REQ_CONFIRM)
3004                 result = 1;
3005               break;
3006
3007             case KSYM_Return:
3008               result = 1;
3009               break;
3010
3011             case KSYM_Escape:
3012               result = 0;
3013               break;
3014
3015             default:
3016               break;
3017           }
3018
3019           if (req_state & REQ_PLAYER)
3020             result = 0;
3021           break;
3022
3023         case EVENT_KEYRELEASE:
3024           ClearPlayerAction();
3025           break;
3026
3027         default:
3028           HandleOtherEvents(&event);
3029           break;
3030       }
3031     }
3032     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3033     {
3034       int joy = AnyJoystick();
3035
3036       if (joy & JOY_BUTTON_1)
3037         result = 1;
3038       else if (joy & JOY_BUTTON_2)
3039         result = 0;
3040     }
3041
3042 #if 1
3043
3044     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3045     {
3046       HandleGameActions();
3047     }
3048     else
3049     {
3050       DoAnimation();
3051
3052       if (!PendingEvent())      /* delay only if no pending events */
3053         Delay(10);
3054     }
3055
3056     BackToFront();
3057
3058 #else
3059
3060     DoAnimation();
3061
3062 #if 1
3063     if (!PendingEvent())        /* delay only if no pending events */
3064       Delay(10);
3065 #else
3066     /* don't eat all CPU time */
3067     Delay(10);
3068 #endif
3069
3070 #endif
3071   }
3072
3073   if (game_status != GAME_MODE_MAIN)
3074     StopAnimation();
3075
3076   UnmapToolButtons();
3077
3078   if (!(req_state & REQ_STAY_OPEN))
3079   {
3080     CloseDoor(DOOR_CLOSE_1);
3081
3082     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3083         (req_state & REQ_REOPEN))
3084       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3085   }
3086
3087   RemapAllGadgets();
3088
3089   if (game_status == GAME_MODE_PLAYING)
3090   {
3091     SetPanelBackground();
3092     SetDrawBackgroundMask(REDRAW_DOOR_1);
3093   }
3094   else
3095   {
3096     SetDrawBackgroundMask(REDRAW_FIELD);
3097   }
3098
3099 #if defined(NETWORK_AVALIABLE)
3100   /* continue network game after request */
3101   if (options.network &&
3102       game_status == GAME_MODE_PLAYING &&
3103       req_state & REQUEST_WAIT_FOR_INPUT)
3104     SendToServer_ContinuePlaying();
3105 #endif
3106
3107   /* restore deactivated drawing when quick-loading level tape recording */
3108   if (tape.playing && tape.deactivate_display)
3109     TapeDeactivateDisplayOn();
3110
3111   return result;
3112 }
3113
3114 unsigned int OpenDoor(unsigned int door_state)
3115 {
3116   if (door_state & DOOR_COPY_BACK)
3117   {
3118     if (door_state & DOOR_OPEN_1)
3119       BlitBitmap(bitmap_db_door, bitmap_db_door,
3120                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
3121                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3122
3123     if (door_state & DOOR_OPEN_2)
3124       BlitBitmap(bitmap_db_door, bitmap_db_door,
3125                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
3126                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3127
3128     door_state &= ~DOOR_COPY_BACK;
3129   }
3130
3131   return MoveDoor(door_state);
3132 }
3133
3134 unsigned int CloseDoor(unsigned int door_state)
3135 {
3136   unsigned int old_door_state = GetDoorState();
3137
3138   if (!(door_state & DOOR_NO_COPY_BACK))
3139   {
3140     if (old_door_state & DOOR_OPEN_1)
3141       BlitBitmap(backbuffer, bitmap_db_door,
3142                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
3143
3144     if (old_door_state & DOOR_OPEN_2)
3145       BlitBitmap(backbuffer, bitmap_db_door,
3146                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
3147
3148     door_state &= ~DOOR_NO_COPY_BACK;
3149   }
3150
3151   return MoveDoor(door_state);
3152 }
3153
3154 unsigned int GetDoorState()
3155 {
3156   return MoveDoor(DOOR_GET_STATE);
3157 }
3158
3159 unsigned int SetDoorState(unsigned int door_state)
3160 {
3161   return MoveDoor(door_state | DOOR_SET_STATE);
3162 }
3163
3164 unsigned int MoveDoor(unsigned int door_state)
3165 {
3166   static int door1 = DOOR_OPEN_1;
3167   static int door2 = DOOR_CLOSE_2;
3168   unsigned long door_delay = 0;
3169   unsigned long door_delay_value;
3170   int stepsize = 1;
3171
3172   if (door_1.width < 0 || door_1.width > DXSIZE)
3173     door_1.width = DXSIZE;
3174   if (door_1.height < 0 || door_1.height > DYSIZE)
3175     door_1.height = DYSIZE;
3176   if (door_2.width < 0 || door_2.width > VXSIZE)
3177     door_2.width = VXSIZE;
3178   if (door_2.height < 0 || door_2.height > VYSIZE)
3179     door_2.height = VYSIZE;
3180
3181   if (door_state == DOOR_GET_STATE)
3182     return (door1 | door2);
3183
3184   if (door_state & DOOR_SET_STATE)
3185   {
3186     if (door_state & DOOR_ACTION_1)
3187       door1 = door_state & DOOR_ACTION_1;
3188     if (door_state & DOOR_ACTION_2)
3189       door2 = door_state & DOOR_ACTION_2;
3190
3191     return (door1 | door2);
3192   }
3193
3194   if (!(door_state & DOOR_FORCE_REDRAW))
3195   {
3196     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3197       door_state &= ~DOOR_OPEN_1;
3198     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3199       door_state &= ~DOOR_CLOSE_1;
3200     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3201       door_state &= ~DOOR_OPEN_2;
3202     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
3203       door_state &= ~DOOR_CLOSE_2;
3204   }
3205
3206   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
3207                       door_2.step_delay);
3208
3209   if (setup.quick_doors)
3210   {
3211     stepsize = 20;              /* must be chosen to always draw last frame */
3212     door_delay_value = 0;
3213   }
3214
3215   if (global.autoplay_leveldir)
3216   {
3217     door_state |= DOOR_NO_DELAY;
3218     door_state &= ~DOOR_CLOSE_ALL;
3219   }
3220
3221 #if 1
3222   if (game_status == GAME_MODE_EDITOR)
3223     door_state |= DOOR_NO_DELAY;
3224 #endif
3225
3226   if (door_state & DOOR_ACTION)
3227   {
3228     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
3229     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
3230     boolean door_1_done = (!handle_door_1);
3231     boolean door_2_done = (!handle_door_2);
3232     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
3233     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
3234     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
3235     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
3236     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
3237     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
3238     int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
3239     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
3240     int door_skip = max_door_size - door_size;
3241     int end = door_size;
3242     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
3243     int k;
3244
3245     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
3246     {
3247       /* opening door sound has priority over simultaneously closing door */
3248       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
3249         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
3250       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
3251         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
3252     }
3253
3254     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
3255     {
3256       int x = k;
3257       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3258       GC gc = bitmap->stored_clip_gc;
3259
3260       if (door_state & DOOR_ACTION_1)
3261       {
3262         int a = MIN(x * door_1.step_offset, end);
3263         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
3264         int i = p + door_skip;
3265
3266         if (door_1.anim_mode & ANIM_STATIC_PANEL)
3267         {
3268           BlitBitmap(bitmap_db_door, drawto,
3269                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
3270                      DXSIZE, DYSIZE, DX, DY);
3271         }
3272         else if (x <= a)
3273         {
3274           BlitBitmap(bitmap_db_door, drawto,
3275                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
3276                      DXSIZE, DYSIZE - p / 2, DX, DY);
3277
3278           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
3279         }
3280
3281         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
3282         {
3283           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3284           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
3285           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
3286           int dst2_x = DX,              dst2_y = DY;
3287           int width = i, height = DYSIZE;
3288
3289           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3290           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3291                            dst1_x, dst1_y);
3292
3293           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3294           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3295                            dst2_x, dst2_y);
3296         }
3297         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
3298         {
3299           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
3300           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
3301           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
3302           int dst2_x = DX,              dst2_y = DY;
3303           int width = DXSIZE, height = i;
3304
3305           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3306           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3307                            dst1_x, dst1_y);
3308
3309           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3310           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3311                            dst2_x, dst2_y);
3312         }
3313         else if (x <= DXSIZE)   /* ANIM_DEFAULT */
3314         {
3315           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
3316
3317           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3318           BlitBitmapMasked(bitmap, drawto,
3319                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
3320                            DX + DXSIZE - i, DY + j);
3321           BlitBitmapMasked(bitmap, drawto,
3322                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
3323                            DX + DXSIZE - i, DY + 140 + j);
3324           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
3325                         DY - (DOOR_GFX_PAGEY1 + j));
3326           BlitBitmapMasked(bitmap, drawto,
3327                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
3328                            DX, DY);
3329           BlitBitmapMasked(bitmap, drawto,
3330                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
3331                            DX, DY + 140 - j);
3332
3333           BlitBitmapMasked(bitmap, drawto,
3334                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
3335                            DX, DY + 77 - j);
3336           BlitBitmapMasked(bitmap, drawto,
3337                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
3338                            DX, DY + 203 - j);
3339           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
3340           BlitBitmapMasked(bitmap, drawto,
3341                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
3342                            DX + DXSIZE - i, DY + 77 + j);
3343           BlitBitmapMasked(bitmap, drawto,
3344                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
3345                            DX + DXSIZE - i, DY + 203 + j);
3346         }
3347
3348         redraw_mask |= REDRAW_DOOR_1;
3349         door_1_done = (a == end);
3350       }
3351
3352       if (door_state & DOOR_ACTION_2)
3353       {
3354         int a = MIN(x * door_2.step_offset, door_size);
3355         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
3356         int i = p + door_skip;
3357
3358         if (door_2.anim_mode & ANIM_STATIC_PANEL)
3359         {
3360           BlitBitmap(bitmap_db_door, drawto,
3361                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
3362                      VXSIZE, VYSIZE, VX, VY);
3363         }
3364         else if (x <= VYSIZE)
3365         {
3366           BlitBitmap(bitmap_db_door, drawto,
3367                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
3368                      VXSIZE, VYSIZE - p / 2, VX, VY);
3369
3370           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
3371         }
3372
3373         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
3374         {
3375           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3376           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
3377           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
3378           int dst2_x = VX,              dst2_y = VY;
3379           int width = i, height = VYSIZE;
3380
3381           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3382           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3383                            dst1_x, dst1_y);
3384
3385           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3386           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3387                            dst2_x, dst2_y);
3388         }
3389         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
3390         {
3391           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
3392           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
3393           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
3394           int dst2_x = VX,              dst2_y = VY;
3395           int width = VXSIZE, height = i;
3396
3397           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
3398           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
3399                            dst1_x, dst1_y);
3400
3401           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
3402           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
3403                            dst2_x, dst2_y);
3404         }
3405         else if (x <= VXSIZE)   /* ANIM_DEFAULT */
3406         {
3407           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
3408
3409           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3410           BlitBitmapMasked(bitmap, drawto,
3411                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
3412                            VX + VXSIZE - i, VY + j);
3413           SetClipOrigin(bitmap, gc,
3414                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
3415           BlitBitmapMasked(bitmap, drawto,
3416                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
3417                            VX, VY);
3418
3419           BlitBitmapMasked(bitmap, drawto,
3420                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3421                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
3422           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
3423           BlitBitmapMasked(bitmap, drawto,
3424                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
3425                            i, VYSIZE / 2 - j,
3426                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
3427         }
3428
3429         redraw_mask |= REDRAW_DOOR_2;
3430         door_2_done = (a == VXSIZE);
3431       }
3432
3433       if (!(door_state & DOOR_NO_DELAY))
3434       {
3435         BackToFront();
3436
3437         if (game_status == GAME_MODE_MAIN)
3438           DoAnimation();
3439
3440         WaitUntilDelayReached(&door_delay, door_delay_value);
3441       }
3442     }
3443   }
3444
3445   if (door_state & DOOR_ACTION_1)
3446     door1 = door_state & DOOR_ACTION_1;
3447   if (door_state & DOOR_ACTION_2)
3448     door2 = door_state & DOOR_ACTION_2;
3449
3450   return (door1 | door2);
3451 }
3452
3453 void DrawSpecialEditorDoor()
3454 {
3455   /* draw bigger toolbox window */
3456   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
3457              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
3458              EX - 4, EY - 12);
3459   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3460              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
3461              EX - 6, EY - 4);
3462
3463   redraw_mask |= REDRAW_ALL;
3464 }
3465
3466 void UndrawSpecialEditorDoor()
3467 {
3468   /* draw normal tape recorder window */
3469   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
3470              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
3471              EX - 6, EY - 12);
3472
3473   redraw_mask |= REDRAW_ALL;
3474 }
3475
3476
3477 /* ---------- new tool button stuff ---------------------------------------- */
3478
3479 /* graphic position values for tool buttons */
3480 #define TOOL_BUTTON_YES_XPOS            2
3481 #define TOOL_BUTTON_YES_YPOS            250
3482 #define TOOL_BUTTON_YES_GFX_YPOS        0
3483 #define TOOL_BUTTON_YES_XSIZE           46
3484 #define TOOL_BUTTON_YES_YSIZE           28
3485 #define TOOL_BUTTON_NO_XPOS             52
3486 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
3487 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
3488 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
3489 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
3490 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
3491 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
3492 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
3493 #define TOOL_BUTTON_CONFIRM_XSIZE       96
3494 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
3495 #define TOOL_BUTTON_PLAYER_XSIZE        30
3496 #define TOOL_BUTTON_PLAYER_YSIZE        30
3497 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
3498 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
3499 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
3500 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
3501 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3502                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3503 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3504                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3505 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3506                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
3507 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
3508                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
3509 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3510                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3511 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3512                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
3513 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3514                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3515 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
3516                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
3517
3518 static struct
3519 {
3520   int xpos, ypos;
3521   int x, y;
3522   int width, height;
3523   int gadget_id;
3524   char *infotext;
3525 } toolbutton_info[NUM_TOOL_BUTTONS] =
3526 {
3527   {
3528     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
3529     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
3530     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
3531     TOOL_CTRL_ID_YES,
3532     "yes"
3533   },
3534   {
3535     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
3536     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
3537     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
3538     TOOL_CTRL_ID_NO,
3539     "no"
3540   },
3541   {
3542     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
3543     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
3544     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
3545     TOOL_CTRL_ID_CONFIRM,
3546     "confirm"
3547   },
3548   {
3549     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3550     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
3551     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3552     TOOL_CTRL_ID_PLAYER_1,
3553     "player 1"
3554   },
3555   {
3556     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3557     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
3558     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3559     TOOL_CTRL_ID_PLAYER_2,
3560     "player 2"
3561   },
3562   {
3563     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3564     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
3565     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3566     TOOL_CTRL_ID_PLAYER_3,
3567     "player 3"
3568   },
3569   {
3570     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
3571     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
3572     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
3573     TOOL_CTRL_ID_PLAYER_4,
3574     "player 4"
3575   }
3576 };
3577
3578 void CreateToolButtons()
3579 {
3580   int i;
3581
3582   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3583   {
3584     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
3585     Bitmap *deco_bitmap = None;
3586     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
3587     struct GadgetInfo *gi;
3588     unsigned long event_mask;
3589     int gd_xoffset, gd_yoffset;
3590     int gd_x1, gd_x2, gd_y;
3591     int id = i;
3592
3593     event_mask = GD_EVENT_RELEASED;
3594
3595     gd_xoffset = toolbutton_info[i].xpos;
3596     gd_yoffset = toolbutton_info[i].ypos;
3597     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
3598     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
3599     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
3600
3601     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
3602     {
3603       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
3604
3605       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
3606                            &deco_bitmap, &deco_x, &deco_y);
3607       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
3608       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
3609     }
3610
3611     gi = CreateGadget(GDI_CUSTOM_ID, id,
3612                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
3613                       GDI_X, DX + toolbutton_info[i].x,
3614                       GDI_Y, DY + toolbutton_info[i].y,
3615                       GDI_WIDTH, toolbutton_info[i].width,
3616                       GDI_HEIGHT, toolbutton_info[i].height,
3617                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
3618                       GDI_STATE, GD_BUTTON_UNPRESSED,
3619                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
3620                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
3621                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
3622                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
3623                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
3624                       GDI_DECORATION_SHIFTING, 1, 1,
3625                       GDI_DIRECT_DRAW, FALSE,
3626                       GDI_EVENT_MASK, event_mask,
3627                       GDI_CALLBACK_ACTION, HandleToolButtons,
3628                       GDI_END);
3629
3630     if (gi == NULL)
3631       Error(ERR_EXIT, "cannot create gadget");
3632
3633     tool_gadget[id] = gi;
3634   }
3635 }
3636
3637 void FreeToolButtons()
3638 {
3639   int i;
3640
3641   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3642     FreeGadget(tool_gadget[i]);
3643 }
3644
3645 static void UnmapToolButtons()
3646 {
3647   int i;
3648
3649   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
3650     UnmapGadget(tool_gadget[i]);
3651 }
3652
3653 static void HandleToolButtons(struct GadgetInfo *gi)
3654 {
3655   request_gadget_id = gi->custom_id;
3656 }
3657
3658 static struct Mapping_EM_to_RND_object
3659 {
3660   int element_em;
3661   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
3662   boolean is_backside;                  /* backside of moving element */
3663
3664   int element_rnd;
3665   int action;
3666   int direction;
3667 }
3668 em_object_mapping_list[] =
3669 {
3670   {
3671     Xblank,                             TRUE,   FALSE,
3672     EL_EMPTY,                           -1, -1
3673   },
3674   {
3675     Yacid_splash_eB,                    FALSE,  FALSE,
3676     EL_ACID_SPLASH_RIGHT,               -1, -1
3677   },
3678   {
3679     Yacid_splash_wB,                    FALSE,  FALSE,
3680     EL_ACID_SPLASH_LEFT,                -1, -1
3681   },
3682
3683 #ifdef EM_ENGINE_BAD_ROLL
3684   {
3685     Xstone_force_e,                     FALSE,  FALSE,
3686     EL_ROCK,                            -1, MV_BIT_RIGHT
3687   },
3688   {
3689     Xstone_force_w,                     FALSE,  FALSE,
3690     EL_ROCK,                            -1, MV_BIT_LEFT
3691   },
3692   {
3693     Xnut_force_e,                       FALSE,  FALSE,
3694     EL_NUT,                             -1, MV_BIT_RIGHT
3695   },
3696   {
3697     Xnut_force_w,                       FALSE,  FALSE,
3698     EL_NUT,                             -1, MV_BIT_LEFT
3699   },
3700   {
3701     Xspring_force_e,                    FALSE,  FALSE,
3702     EL_SPRING,                          -1, MV_BIT_RIGHT
3703   },
3704   {
3705     Xspring_force_w,                    FALSE,  FALSE,
3706     EL_SPRING,                          -1, MV_BIT_LEFT
3707   },
3708   {
3709     Xemerald_force_e,                   FALSE,  FALSE,
3710     EL_EMERALD,                         -1, MV_BIT_RIGHT
3711   },
3712   {
3713     Xemerald_force_w,                   FALSE,  FALSE,
3714     EL_EMERALD,                         -1, MV_BIT_LEFT
3715   },
3716   {
3717     Xdiamond_force_e,                   FALSE,  FALSE,
3718     EL_DIAMOND,                         -1, MV_BIT_RIGHT
3719   },
3720   {
3721     Xdiamond_force_w,                   FALSE,  FALSE,
3722     EL_DIAMOND,                         -1, MV_BIT_LEFT
3723   },
3724   {
3725     Xbomb_force_e,                      FALSE,  FALSE,
3726     EL_BOMB,                            -1, MV_BIT_RIGHT
3727   },
3728   {
3729     Xbomb_force_w,                      FALSE,  FALSE,
3730     EL_BOMB,                            -1, MV_BIT_LEFT
3731   },
3732 #endif  /* EM_ENGINE_BAD_ROLL */
3733
3734   {
3735     Xstone,                             TRUE,   FALSE,
3736     EL_ROCK,                            -1, -1
3737   },
3738   {
3739     Xstone_pause,                       FALSE,  FALSE,
3740     EL_ROCK,                            -1, -1
3741   },
3742   {
3743     Xstone_fall,                        FALSE,  FALSE,
3744     EL_ROCK,                            -1, -1
3745   },
3746   {
3747     Ystone_s,                           FALSE,  FALSE,
3748     EL_ROCK,                            ACTION_FALLING, -1
3749   },
3750   {
3751     Ystone_sB,                          FALSE,  TRUE,
3752     EL_ROCK,                            ACTION_FALLING, -1
3753   },
3754   {
3755     Ystone_e,                           FALSE,  FALSE,
3756     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3757   },
3758   {
3759     Ystone_eB,                          FALSE,  TRUE,
3760     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
3761   },
3762   {
3763     Ystone_w,                           FALSE,  FALSE,
3764     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3765   },
3766   {
3767     Ystone_wB,                          FALSE,  TRUE,
3768     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
3769   },
3770   {
3771     Xnut,                               TRUE,   FALSE,
3772     EL_NUT,                             -1, -1
3773   },
3774   {
3775     Xnut_pause,                         FALSE,  FALSE,
3776     EL_NUT,                             -1, -1
3777   },
3778   {
3779     Xnut_fall,                          FALSE,  FALSE,
3780     EL_NUT,                             -1, -1
3781   },
3782   {
3783     Ynut_s,                             FALSE,  FALSE,
3784     EL_NUT,                             ACTION_FALLING, -1
3785   },
3786   {
3787     Ynut_sB,                            FALSE,  TRUE,
3788     EL_NUT,                             ACTION_FALLING, -1
3789   },
3790   {
3791     Ynut_e,                             FALSE,  FALSE,
3792     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3793   },
3794   {
3795     Ynut_eB,                            FALSE,  TRUE,
3796     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
3797   },
3798   {
3799     Ynut_w,                             FALSE,  FALSE,
3800     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3801   },
3802   {
3803     Ynut_wB,                            FALSE,  TRUE,
3804     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
3805   },
3806   {
3807     Xbug_n,                             TRUE,   FALSE,
3808     EL_BUG_UP,                          -1, -1
3809   },
3810   {
3811     Xbug_e,                             TRUE,   FALSE,
3812     EL_BUG_RIGHT,                       -1, -1
3813   },
3814   {
3815     Xbug_s,                             TRUE,   FALSE,
3816     EL_BUG_DOWN,                        -1, -1
3817   },
3818   {
3819     Xbug_w,                             TRUE,   FALSE,
3820     EL_BUG_LEFT,                        -1, -1
3821   },
3822   {
3823     Xbug_gon,                           FALSE,  FALSE,
3824     EL_BUG_UP,                          -1, -1
3825   },
3826   {
3827     Xbug_goe,                           FALSE,  FALSE,
3828     EL_BUG_RIGHT,                       -1, -1
3829   },
3830   {
3831     Xbug_gos,                           FALSE,  FALSE,
3832     EL_BUG_DOWN,                        -1, -1
3833   },
3834   {
3835     Xbug_gow,                           FALSE,  FALSE,
3836     EL_BUG_LEFT,                        -1, -1
3837   },
3838   {
3839     Ybug_n,                             FALSE,  FALSE,
3840     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3841   },
3842   {
3843     Ybug_nB,                            FALSE,  TRUE,
3844     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
3845   },
3846   {
3847     Ybug_e,                             FALSE,  FALSE,
3848     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3849   },
3850   {
3851     Ybug_eB,                            FALSE,  TRUE,
3852     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
3853   },
3854   {
3855     Ybug_s,                             FALSE,  FALSE,
3856     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3857   },
3858   {
3859     Ybug_sB,                            FALSE,  TRUE,
3860     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
3861   },
3862   {
3863     Ybug_w,                             FALSE,  FALSE,
3864     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3865   },
3866   {
3867     Ybug_wB,                            FALSE,  TRUE,
3868     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
3869   },
3870   {
3871     Ybug_w_n,                           FALSE,  FALSE,
3872     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3873   },
3874   {
3875     Ybug_n_e,                           FALSE,  FALSE,
3876     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3877   },
3878   {
3879     Ybug_e_s,                           FALSE,  FALSE,
3880     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3881   },
3882   {
3883     Ybug_s_w,                           FALSE,  FALSE,
3884     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3885   },
3886   {
3887     Ybug_e_n,                           FALSE,  FALSE,
3888     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3889   },
3890   {
3891     Ybug_s_e,                           FALSE,  FALSE,
3892     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3893   },
3894   {
3895     Ybug_w_s,                           FALSE,  FALSE,
3896     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
3897   },
3898   {
3899     Ybug_n_w,                           FALSE,  FALSE,
3900     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
3901   },
3902   {
3903     Ybug_stone,                         FALSE,  FALSE,
3904     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
3905   },
3906   {
3907     Ybug_spring,                        FALSE,  FALSE,
3908     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
3909   },
3910   {
3911     Xtank_n,                            TRUE,   FALSE,
3912     EL_SPACESHIP_UP,                    -1, -1
3913   },
3914   {
3915     Xtank_e,                            TRUE,   FALSE,
3916     EL_SPACESHIP_RIGHT,                 -1, -1
3917   },
3918   {
3919     Xtank_s,                            TRUE,   FALSE,
3920     EL_SPACESHIP_DOWN,                  -1, -1
3921   },
3922   {
3923     Xtank_w,                            TRUE,   FALSE,
3924     EL_SPACESHIP_LEFT,                  -1, -1
3925   },
3926   {
3927     Xtank_gon,                          FALSE,  FALSE,
3928     EL_SPACESHIP_UP,                    -1, -1
3929   },
3930   {
3931     Xtank_goe,                          FALSE,  FALSE,
3932     EL_SPACESHIP_RIGHT,                 -1, -1
3933   },
3934   {
3935     Xtank_gos,                          FALSE,  FALSE,
3936     EL_SPACESHIP_DOWN,                  -1, -1
3937   },
3938   {
3939     Xtank_gow,                          FALSE,  FALSE,
3940     EL_SPACESHIP_LEFT,                  -1, -1
3941   },
3942   {
3943     Ytank_n,                            FALSE,  FALSE,
3944     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3945   },
3946   {
3947     Ytank_nB,                           FALSE,  TRUE,
3948     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
3949   },
3950   {
3951     Ytank_e,                            FALSE,  FALSE,
3952     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3953   },
3954   {
3955     Ytank_eB,                           FALSE,  TRUE,
3956     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
3957   },
3958   {
3959     Ytank_s,                            FALSE,  FALSE,
3960     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3961   },
3962   {
3963     Ytank_sB,                           FALSE,  TRUE,
3964     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
3965   },
3966   {
3967     Ytank_w,                            FALSE,  FALSE,
3968     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3969   },
3970   {
3971     Ytank_wB,                           FALSE,  TRUE,
3972     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
3973   },
3974   {
3975     Ytank_w_n,                          FALSE,  FALSE,
3976     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
3977   },
3978   {
3979     Ytank_n_e,                          FALSE,  FALSE,
3980     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
3981   },
3982   {
3983     Ytank_e_s,                          FALSE,  FALSE,
3984     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
3985   },
3986   {
3987     Ytank_s_w,                          FALSE,  FALSE,
3988     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
3989   },
3990   {
3991     Ytank_e_n,                          FALSE,  FALSE,
3992     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
3993   },
3994   {
3995     Ytank_s_e,                          FALSE,  FALSE,
3996     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
3997   },
3998   {
3999     Ytank_w_s,                          FALSE,  FALSE,
4000     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4001   },
4002   {
4003     Ytank_n_w,                          FALSE,  FALSE,
4004     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4005   },
4006   {
4007     Ytank_stone,                        FALSE,  FALSE,
4008     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
4009   },
4010   {
4011     Ytank_spring,                       FALSE,  FALSE,
4012     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
4013   },
4014   {
4015     Xandroid,                           TRUE,   FALSE,
4016     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
4017   },
4018   {
4019     Xandroid_1_n,                       FALSE,  FALSE,
4020     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4021   },
4022   {
4023     Xandroid_2_n,                       FALSE,  FALSE,
4024     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4025   },
4026   {
4027     Xandroid_1_e,                       FALSE,  FALSE,
4028     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4029   },
4030   {
4031     Xandroid_2_e,                       FALSE,  FALSE,
4032     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4033   },
4034   {
4035     Xandroid_1_w,                       FALSE,  FALSE,
4036     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4037   },
4038   {
4039     Xandroid_2_w,                       FALSE,  FALSE,
4040     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4041   },
4042   {
4043     Xandroid_1_s,                       FALSE,  FALSE,
4044     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4045   },
4046   {
4047     Xandroid_2_s,                       FALSE,  FALSE,
4048     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4049   },
4050   {
4051     Yandroid_n,                         FALSE,  FALSE,
4052     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4053   },
4054   {
4055     Yandroid_nB,                        FALSE,  TRUE,
4056     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4057   },
4058   {
4059     Yandroid_ne,                        FALSE,  FALSE,
4060     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
4061   },
4062   {
4063     Yandroid_neB,                       FALSE,  TRUE,
4064     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
4065   },
4066   {
4067     Yandroid_e,                         FALSE,  FALSE,
4068     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4069   },
4070   {
4071     Yandroid_eB,                        FALSE,  TRUE,
4072     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4073   },
4074   {
4075     Yandroid_se,                        FALSE,  FALSE,
4076     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
4077   },
4078   {
4079     Yandroid_seB,                       FALSE,  TRUE,
4080     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4081   },
4082   {
4083     Yandroid_s,                         FALSE,  FALSE,
4084     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4085   },
4086   {
4087     Yandroid_sB,                        FALSE,  TRUE,
4088     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4089   },
4090   {
4091     Yandroid_sw,                        FALSE,  FALSE,
4092     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
4093   },
4094   {
4095     Yandroid_swB,                       FALSE,  TRUE,
4096     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
4097   },
4098   {
4099     Yandroid_w,                         FALSE,  FALSE,
4100     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4101   },
4102   {
4103     Yandroid_wB,                        FALSE,  TRUE,
4104     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4105   },
4106   {
4107     Yandroid_nw,                        FALSE,  FALSE,
4108     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
4109   },
4110   {
4111     Yandroid_nwB,                       FALSE,  TRUE,
4112     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
4113   },
4114   {
4115     Xspring,                            TRUE,   FALSE,
4116     EL_SPRING,                          -1, -1
4117   },
4118   {
4119     Xspring_pause,                      FALSE,  FALSE,
4120     EL_SPRING,                          -1, -1
4121   },
4122   {
4123     Xspring_e,                          FALSE,  FALSE,
4124     EL_SPRING,                          -1, -1
4125   },
4126   {
4127     Xspring_w,                          FALSE,  FALSE,
4128     EL_SPRING,                          -1, -1
4129   },
4130   {
4131     Xspring_fall,                       FALSE,  FALSE,
4132     EL_SPRING,                          -1, -1
4133   },
4134   {
4135     Yspring_s,                          FALSE,  FALSE,
4136     EL_SPRING,                          ACTION_FALLING, -1
4137   },
4138   {
4139     Yspring_sB,                         FALSE,  TRUE,
4140     EL_SPRING,                          ACTION_FALLING, -1
4141   },
4142   {
4143     Yspring_e,                          FALSE,  FALSE,
4144     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4145   },
4146   {
4147     Yspring_eB,                         FALSE,  TRUE,
4148     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4149   },
4150   {
4151     Yspring_w,                          FALSE,  FALSE,
4152     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4153   },
4154   {
4155     Yspring_wB,                         FALSE,  TRUE,
4156     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4157   },
4158   {
4159     Yspring_kill_e,                     FALSE,  FALSE,
4160     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4161   },
4162   {
4163     Yspring_kill_eB,                    FALSE,  TRUE,
4164     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4165   },
4166   {
4167     Yspring_kill_w,                     FALSE,  FALSE,
4168     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4169   },
4170   {
4171     Yspring_kill_wB,                    FALSE,  TRUE,
4172     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4173   },
4174   {
4175     Xeater_n,                           TRUE,   FALSE,
4176     EL_YAMYAM_UP,                       -1, -1
4177   },
4178   {
4179     Xeater_e,                           TRUE,   FALSE,
4180     EL_YAMYAM_RIGHT,                    -1, -1
4181   },
4182   {
4183     Xeater_w,                           TRUE,   FALSE,
4184     EL_YAMYAM_LEFT,                     -1, -1
4185   },
4186   {
4187     Xeater_s,                           TRUE,   FALSE,
4188     EL_YAMYAM_DOWN,                     -1, -1
4189   },
4190   {
4191     Yeater_n,                           FALSE,  FALSE,
4192     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4193   },
4194   {
4195     Yeater_nB,                          FALSE,  TRUE,
4196     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4197   },
4198   {
4199     Yeater_e,                           FALSE,  FALSE,
4200     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4201   },
4202   {
4203     Yeater_eB,                          FALSE,  TRUE,
4204     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
4205   },
4206   {
4207     Yeater_s,                           FALSE,  FALSE,
4208     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4209   },
4210   {
4211     Yeater_sB,                          FALSE,  TRUE,
4212     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
4213   },
4214   {
4215     Yeater_w,                           FALSE,  FALSE,
4216     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4217   },
4218   {
4219     Yeater_wB,                          FALSE,  TRUE,
4220     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
4221   },
4222   {
4223     Yeater_stone,                       FALSE,  FALSE,
4224     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
4225   },
4226   {
4227     Yeater_spring,                      FALSE,  FALSE,
4228     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
4229   },
4230   {
4231     Xalien,                             TRUE,   FALSE,
4232     EL_ROBOT,                           -1, -1
4233   },
4234   {
4235     Xalien_pause,                       FALSE,  FALSE,
4236     EL_ROBOT,                           -1, -1
4237   },
4238   {
4239     Yalien_n,                           FALSE,  FALSE,
4240     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4241   },
4242   {
4243     Yalien_nB,                          FALSE,  TRUE,
4244     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
4245   },
4246   {
4247     Yalien_e,                           FALSE,  FALSE,
4248     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4249   },
4250   {
4251     Yalien_eB,                          FALSE,  TRUE,
4252     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
4253   },
4254   {
4255     Yalien_s,                           FALSE,  FALSE,
4256     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4257   },
4258   {
4259     Yalien_sB,                          FALSE,  TRUE,
4260     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
4261   },
4262   {
4263     Yalien_w,                           FALSE,  FALSE,
4264     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4265   },
4266   {
4267     Yalien_wB,                          FALSE,  TRUE,
4268     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
4269   },
4270   {
4271     Yalien_stone,                       FALSE,  FALSE,
4272     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
4273   },
4274   {
4275     Yalien_spring,                      FALSE,  FALSE,
4276     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
4277   },
4278   {
4279     Xemerald,                           TRUE,   FALSE,
4280     EL_EMERALD,                         -1, -1
4281   },
4282   {
4283     Xemerald_pause,                     FALSE,  FALSE,
4284     EL_EMERALD,                         -1, -1
4285   },
4286   {
4287     Xemerald_fall,                      FALSE,  FALSE,
4288     EL_EMERALD,                         -1, -1
4289   },
4290   {
4291     Xemerald_shine,                     FALSE,  FALSE,
4292     EL_EMERALD,                         ACTION_TWINKLING, -1
4293   },
4294   {
4295     Yemerald_s,                         FALSE,  FALSE,
4296     EL_EMERALD,                         ACTION_FALLING, -1
4297   },
4298   {
4299     Yemerald_sB,                        FALSE,  TRUE,
4300     EL_EMERALD,                         ACTION_FALLING, -1
4301   },
4302   {
4303     Yemerald_e,                         FALSE,  FALSE,
4304     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4305   },
4306   {
4307     Yemerald_eB,                        FALSE,  TRUE,
4308     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
4309   },
4310   {
4311     Yemerald_w,                         FALSE,  FALSE,
4312     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4313   },
4314   {
4315     Yemerald_wB,                        FALSE,  TRUE,
4316     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
4317   },
4318   {
4319     Yemerald_eat,                       FALSE,  FALSE,
4320     EL_EMERALD,                         ACTION_COLLECTING, -1
4321   },
4322   {
4323     Yemerald_stone,                     FALSE,  FALSE,
4324     EL_NUT,                             ACTION_BREAKING, -1
4325   },
4326   {
4327     Xdiamond,                           TRUE,   FALSE,
4328     EL_DIAMOND,                         -1, -1
4329   },
4330   {
4331     Xdiamond_pause,                     FALSE,  FALSE,
4332     EL_DIAMOND,                         -1, -1
4333   },
4334   {
4335     Xdiamond_fall,                      FALSE,  FALSE,
4336     EL_DIAMOND,                         -1, -1
4337   },
4338   {
4339     Xdiamond_shine,                     FALSE,  FALSE,
4340     EL_DIAMOND,                         ACTION_TWINKLING, -1
4341   },
4342   {
4343     Ydiamond_s,                         FALSE,  FALSE,
4344     EL_DIAMOND,                         ACTION_FALLING, -1
4345   },
4346   {
4347     Ydiamond_sB,                        FALSE,  TRUE,
4348     EL_DIAMOND,                         ACTION_FALLING, -1
4349   },
4350   {
4351     Ydiamond_e,                         FALSE,  FALSE,
4352     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4353   },
4354   {
4355     Ydiamond_eB,                        FALSE,  TRUE,
4356     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
4357   },
4358   {
4359     Ydiamond_w,                         FALSE,  FALSE,
4360     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4361   },
4362   {
4363     Ydiamond_wB,                        FALSE,  TRUE,
4364     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
4365   },
4366   {
4367     Ydiamond_eat,                       FALSE,  FALSE,
4368     EL_DIAMOND,                         ACTION_COLLECTING, -1
4369   },
4370   {
4371     Ydiamond_stone,                     FALSE,  FALSE,
4372     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
4373   },
4374   {
4375     Xdrip_fall,                         TRUE,   FALSE,
4376     EL_AMOEBA_DROP,                     -1, -1
4377   },
4378   {
4379     Xdrip_stretch,                      FALSE,  FALSE,
4380     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4381   },
4382   {
4383     Xdrip_stretchB,                     FALSE,  TRUE,
4384     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4385   },
4386   {
4387     Xdrip_eat,                          FALSE,  FALSE,
4388     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
4389   },
4390   {
4391     Ydrip_s1,                           FALSE,  FALSE,
4392     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4393   },
4394   {
4395     Ydrip_s1B,                          FALSE,  TRUE,
4396     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4397   },
4398   {
4399     Ydrip_s2,                           FALSE,  FALSE,
4400     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4401   },
4402   {
4403     Ydrip_s2B,                          FALSE,  TRUE,
4404     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
4405   },
4406   {
4407     Xbomb,                              TRUE,   FALSE,
4408     EL_BOMB,                            -1, -1
4409   },
4410   {
4411     Xbomb_pause,                        FALSE,  FALSE,
4412     EL_BOMB,                            -1, -1
4413   },
4414   {
4415     Xbomb_fall,                         FALSE,  FALSE,
4416     EL_BOMB,                            -1, -1
4417   },
4418   {
4419     Ybomb_s,                            FALSE,  FALSE,
4420     EL_BOMB,                            ACTION_FALLING, -1
4421   },
4422   {
4423     Ybomb_sB,                           FALSE,  TRUE,
4424     EL_BOMB,                            ACTION_FALLING, -1
4425   },
4426   {
4427     Ybomb_e,                            FALSE,  FALSE,
4428     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4429   },
4430   {
4431     Ybomb_eB,                           FALSE,  TRUE,
4432     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
4433   },
4434   {
4435     Ybomb_w,                            FALSE,  FALSE,
4436     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4437   },
4438   {
4439     Ybomb_wB,                           FALSE,  TRUE,
4440     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
4441   },
4442   {
4443     Ybomb_eat,                          FALSE,  FALSE,
4444     EL_BOMB,                            ACTION_ACTIVATING, -1
4445   },
4446   {
4447     Xballoon,                           TRUE,   FALSE,
4448     EL_BALLOON,                         -1, -1
4449   },
4450   {
4451     Yballoon_n,                         FALSE,  FALSE,
4452     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4453   },
4454   {
4455     Yballoon_nB,                        FALSE,  TRUE,
4456     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
4457   },
4458   {
4459     Yballoon_e,                         FALSE,  FALSE,
4460     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4461   },
4462   {
4463     Yballoon_eB,                        FALSE,  TRUE,
4464     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
4465   },
4466   {
4467     Yballoon_s,                         FALSE,  FALSE,
4468     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4469   },
4470   {
4471     Yballoon_sB,                        FALSE,  TRUE,
4472     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
4473   },
4474   {
4475     Yballoon_w,                         FALSE,  FALSE,
4476     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4477   },
4478   {
4479     Yballoon_wB,                        FALSE,  TRUE,
4480     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
4481   },
4482   {
4483     Xgrass,                             TRUE,   FALSE,
4484     EL_EMC_GRASS,                       -1, -1
4485   },
4486   {
4487     Ygrass_nB,                          FALSE,  FALSE,
4488     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
4489   },
4490   {
4491     Ygrass_eB,                          FALSE,  FALSE,
4492     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
4493   },
4494   {
4495     Ygrass_sB,                          FALSE,  FALSE,
4496     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
4497   },
4498   {
4499     Ygrass_wB,                          FALSE,  FALSE,
4500     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
4501   },
4502   {
4503     Xdirt,                              TRUE,   FALSE,
4504     EL_SAND,                            -1, -1
4505   },
4506   {
4507     Ydirt_nB,                           FALSE,  FALSE,
4508     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
4509   },
4510   {
4511     Ydirt_eB,                           FALSE,  FALSE,
4512     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
4513   },
4514   {
4515     Ydirt_sB,                           FALSE,  FALSE,
4516     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
4517   },
4518   {
4519     Ydirt_wB,                           FALSE,  FALSE,
4520     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
4521   },
4522   {
4523     Xacid_ne,                           TRUE,   FALSE,
4524     EL_ACID_POOL_TOPRIGHT,              -1, -1
4525   },
4526   {
4527     Xacid_se,                           TRUE,   FALSE,
4528     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
4529   },
4530   {
4531     Xacid_s,                            TRUE,   FALSE,
4532     EL_ACID_POOL_BOTTOM,                -1, -1
4533   },
4534   {
4535     Xacid_sw,                           TRUE,   FALSE,
4536     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
4537   },
4538   {
4539     Xacid_nw,                           TRUE,   FALSE,
4540     EL_ACID_POOL_TOPLEFT,               -1, -1
4541   },
4542   {
4543     Xacid_1,                            TRUE,   FALSE,
4544     EL_ACID,                            -1, -1
4545   },
4546   {
4547     Xacid_2,                            FALSE,  FALSE,
4548     EL_ACID,                            -1, -1
4549   },
4550   {
4551     Xacid_3,                            FALSE,  FALSE,
4552     EL_ACID,                            -1, -1
4553   },
4554   {
4555     Xacid_4,                            FALSE,  FALSE,
4556     EL_ACID,                            -1, -1
4557   },
4558   {
4559     Xacid_5,                            FALSE,  FALSE,
4560     EL_ACID,                            -1, -1
4561   },
4562   {
4563     Xacid_6,                            FALSE,  FALSE,
4564     EL_ACID,                            -1, -1
4565   },
4566   {
4567     Xacid_7,                            FALSE,  FALSE,
4568     EL_ACID,                            -1, -1
4569   },
4570   {
4571     Xacid_8,                            FALSE,  FALSE,
4572     EL_ACID,                            -1, -1
4573   },
4574   {
4575     Xball_1,                            TRUE,   FALSE,
4576     EL_EMC_MAGIC_BALL,                  -1, -1
4577   },
4578   {
4579     Xball_1B,                           FALSE,  FALSE,
4580     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4581   },
4582   {
4583     Xball_2,                            FALSE,  FALSE,
4584     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4585   },
4586   {
4587     Xball_2B,                           FALSE,  FALSE,
4588     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
4589   },
4590   {
4591     Yball_eat,                          FALSE,  FALSE,
4592     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
4593   },
4594   {
4595     Ykey_1_eat,                         FALSE,  FALSE,
4596     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
4597   },
4598   {
4599     Ykey_2_eat,                         FALSE,  FALSE,
4600     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
4601   },
4602   {
4603     Ykey_3_eat,                         FALSE,  FALSE,
4604     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
4605   },
4606   {
4607     Ykey_4_eat,                         FALSE,  FALSE,
4608     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
4609   },
4610   {
4611     Ykey_5_eat,                         FALSE,  FALSE,
4612     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
4613   },
4614   {
4615     Ykey_6_eat,                         FALSE,  FALSE,
4616     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
4617   },
4618   {
4619     Ykey_7_eat,                         FALSE,  FALSE,
4620     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
4621   },
4622   {
4623     Ykey_8_eat,                         FALSE,  FALSE,
4624     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
4625   },
4626   {
4627     Ylenses_eat,                        FALSE,  FALSE,
4628     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
4629   },
4630   {
4631     Ymagnify_eat,                       FALSE,  FALSE,
4632     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
4633   },
4634   {
4635     Ygrass_eat,                         FALSE,  FALSE,
4636     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
4637   },
4638   {
4639     Ydirt_eat,                          FALSE,  FALSE,
4640     EL_SAND,                            ACTION_SNAPPING, -1
4641   },
4642   {
4643     Xgrow_ns,                           TRUE,   FALSE,
4644     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
4645   },
4646   {
4647     Ygrow_ns_eat,                       FALSE,  FALSE,
4648     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
4649   },
4650   {
4651     Xgrow_ew,                           TRUE,   FALSE,
4652     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
4653   },
4654   {
4655     Ygrow_ew_eat,                       FALSE,  FALSE,
4656     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
4657   },
4658   {
4659     Xwonderwall,                        TRUE,   FALSE,
4660     EL_MAGIC_WALL,                      -1, -1
4661   },
4662   {
4663     XwonderwallB,                       FALSE,  FALSE,
4664     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
4665   },
4666   {
4667     Xamoeba_1,                          TRUE,   FALSE,
4668     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4669   },
4670   {
4671     Xamoeba_2,                          FALSE,  FALSE,
4672     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4673   },
4674   {
4675     Xamoeba_3,                          FALSE,  FALSE,
4676     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4677   },
4678   {
4679     Xamoeba_4,                          FALSE,  FALSE,
4680     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
4681   },
4682   {
4683     Xamoeba_5,                          TRUE,   FALSE,
4684     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4685   },
4686   {
4687     Xamoeba_6,                          FALSE,  FALSE,
4688     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4689   },
4690   {
4691     Xamoeba_7,                          FALSE,  FALSE,
4692     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4693   },
4694   {
4695     Xamoeba_8,                          FALSE,  FALSE,
4696     EL_AMOEBA_WET,                      ACTION_OTHER, -1
4697   },
4698   {
4699     Xdoor_1,                            TRUE,   FALSE,
4700     EL_EM_GATE_1,                       -1, -1
4701   },
4702   {
4703     Xdoor_2,                            TRUE,   FALSE,
4704     EL_EM_GATE_2,                       -1, -1
4705   },
4706   {
4707     Xdoor_3,                            TRUE,   FALSE,
4708     EL_EM_GATE_3,                       -1, -1
4709   },
4710   {
4711     Xdoor_4,                            TRUE,   FALSE,
4712     EL_EM_GATE_4,                       -1, -1
4713   },
4714   {
4715     Xdoor_5,                            TRUE,   FALSE,
4716     EL_EMC_GATE_5,                      -1, -1
4717   },
4718   {
4719     Xdoor_6,                            TRUE,   FALSE,
4720     EL_EMC_GATE_6,                      -1, -1
4721   },
4722   {
4723     Xdoor_7,                            TRUE,   FALSE,
4724     EL_EMC_GATE_7,                      -1, -1
4725   },
4726   {
4727     Xdoor_8,                            TRUE,   FALSE,
4728     EL_EMC_GATE_8,                      -1, -1
4729   },
4730   {
4731     Xkey_1,                             TRUE,   FALSE,
4732     EL_EM_KEY_1,                        -1, -1
4733   },
4734   {
4735     Xkey_2,                             TRUE,   FALSE,
4736     EL_EM_KEY_2,                        -1, -1
4737   },
4738   {
4739     Xkey_3,                             TRUE,   FALSE,
4740     EL_EM_KEY_3,                        -1, -1
4741   },
4742   {
4743     Xkey_4,                             TRUE,   FALSE,
4744     EL_EM_KEY_4,                        -1, -1
4745   },
4746   {
4747     Xkey_5,                             TRUE,   FALSE,
4748     EL_EMC_KEY_5,                       -1, -1
4749   },
4750   {
4751     Xkey_6,                             TRUE,   FALSE,
4752     EL_EMC_KEY_6,                       -1, -1
4753   },
4754   {
4755     Xkey_7,                             TRUE,   FALSE,
4756     EL_EMC_KEY_7,                       -1, -1
4757   },
4758   {
4759     Xkey_8,                             TRUE,   FALSE,
4760     EL_EMC_KEY_8,                       -1, -1
4761   },
4762   {
4763     Xwind_n,                            TRUE,   FALSE,
4764     EL_BALLOON_SWITCH_UP,               -1, -1
4765   },
4766   {
4767     Xwind_e,                            TRUE,   FALSE,
4768     EL_BALLOON_SWITCH_RIGHT,            -1, -1
4769   },
4770   {
4771     Xwind_s,                            TRUE,   FALSE,
4772     EL_BALLOON_SWITCH_DOWN,             -1, -1
4773   },
4774   {
4775     Xwind_w,                            TRUE,   FALSE,
4776     EL_BALLOON_SWITCH_LEFT,             -1, -1
4777   },
4778   {
4779     Xwind_nesw,                         TRUE,   FALSE,
4780     EL_BALLOON_SWITCH_ANY,              -1, -1
4781   },
4782   {
4783     Xwind_stop,                         TRUE,   FALSE,
4784     EL_BALLOON_SWITCH_NONE,             -1, -1
4785   },
4786   {
4787     Xexit,                              TRUE,   FALSE,
4788     EL_EM_EXIT_CLOSED,                  -1, -1
4789   },
4790   {
4791     Xexit_1,                            TRUE,   FALSE,
4792     EL_EM_EXIT_OPEN,                    -1, -1
4793   },
4794   {
4795     Xexit_2,                            FALSE,  FALSE,
4796     EL_EM_EXIT_OPEN,                    -1, -1
4797   },
4798   {
4799     Xexit_3,                            FALSE,  FALSE,
4800     EL_EM_EXIT_OPEN,                    -1, -1
4801   },
4802   {
4803     Xdynamite,                          TRUE,   FALSE,
4804     EL_EM_DYNAMITE,                     -1, -1
4805   },
4806   {
4807     Ydynamite_eat,                      FALSE,  FALSE,
4808     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
4809   },
4810   {
4811     Xdynamite_1,                        TRUE,   FALSE,
4812     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4813   },
4814   {
4815     Xdynamite_2,                        FALSE,  FALSE,
4816     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4817   },
4818   {
4819     Xdynamite_3,                        FALSE,  FALSE,
4820     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4821   },
4822   {
4823     Xdynamite_4,                        FALSE,  FALSE,
4824     EL_EM_DYNAMITE_ACTIVE,              -1, -1
4825   },
4826   {
4827     Xbumper,                            TRUE,   FALSE,
4828     EL_EMC_SPRING_BUMPER,               -1, -1
4829   },
4830   {
4831     XbumperB,                           FALSE,  FALSE,
4832     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
4833   },
4834   {
4835     Xwheel,                             TRUE,   FALSE,
4836     EL_ROBOT_WHEEL,                     -1, -1
4837   },
4838   {
4839     XwheelB,                            FALSE,  FALSE,
4840     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
4841   },
4842   {
4843     Xswitch,                            TRUE,   FALSE,
4844     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
4845   },
4846   {
4847     XswitchB,                           FALSE,  FALSE,
4848     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
4849   },
4850   {
4851     Xsand,                              TRUE,   FALSE,
4852     EL_QUICKSAND_EMPTY,                 -1, -1
4853   },
4854   {
4855     Xsand_stone,                        TRUE,   FALSE,
4856     EL_QUICKSAND_FULL,                  -1, -1
4857   },
4858   {
4859     Xsand_stonein_1,                    FALSE,  TRUE,
4860     EL_ROCK,                            ACTION_FILLING, -1
4861   },
4862   {
4863     Xsand_stonein_2,                    FALSE,  TRUE,
4864     EL_ROCK,                            ACTION_FILLING, -1
4865   },
4866   {
4867     Xsand_stonein_3,                    FALSE,  TRUE,
4868     EL_ROCK,                            ACTION_FILLING, -1
4869   },
4870   {
4871     Xsand_stonein_4,                    FALSE,  TRUE,
4872     EL_ROCK,                            ACTION_FILLING, -1
4873   },
4874 #if 1
4875   {
4876     Xsand_stonesand_1,                  FALSE,  FALSE,
4877     EL_QUICKSAND_EMPTYING,              -1, -1
4878   },
4879   {
4880     Xsand_stonesand_2,                  FALSE,  FALSE,
4881     EL_QUICKSAND_EMPTYING,              -1, -1
4882   },
4883   {
4884     Xsand_stonesand_3,                  FALSE,  FALSE,
4885     EL_QUICKSAND_EMPTYING,              -1, -1
4886   },
4887   {
4888     Xsand_stonesand_4,                  FALSE,  FALSE,
4889     EL_QUICKSAND_EMPTYING,              -1, -1
4890   },
4891   {
4892     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
4893     EL_QUICKSAND_EMPTYING,              -1, -1
4894   },
4895   {
4896     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
4897     EL_QUICKSAND_EMPTYING,              -1, -1
4898   },
4899 #else
4900   {
4901     Xsand_stonesand_1,                  FALSE,  FALSE,
4902     EL_QUICKSAND_FULL,                  -1, -1
4903   },
4904   {
4905     Xsand_stonesand_2,                  FALSE,  FALSE,
4906     EL_QUICKSAND_FULL,                  -1, -1
4907   },
4908   {
4909     Xsand_stonesand_3,                  FALSE,  FALSE,
4910     EL_QUICKSAND_FULL,                  -1, -1
4911   },
4912   {
4913     Xsand_stonesand_4,                  FALSE,  FALSE,
4914     EL_QUICKSAND_FULL,                  -1, -1
4915   },
4916 #endif
4917   {
4918     Xsand_stoneout_1,                   FALSE,  FALSE,
4919     EL_ROCK,                            ACTION_EMPTYING, -1
4920   },
4921   {
4922     Xsand_stoneout_2,                   FALSE,  FALSE,
4923     EL_ROCK,                            ACTION_EMPTYING, -1
4924   },
4925 #if 1
4926   {
4927     Xsand_sandstone_1,                  FALSE,  FALSE,
4928     EL_QUICKSAND_FILLING,               -1, -1
4929   },
4930   {
4931     Xsand_sandstone_2,                  FALSE,  FALSE,
4932     EL_QUICKSAND_FILLING,               -1, -1
4933   },
4934   {
4935     Xsand_sandstone_3,                  FALSE,  FALSE,
4936     EL_QUICKSAND_FILLING,               -1, -1
4937   },
4938   {
4939     Xsand_sandstone_4,                  FALSE,  FALSE,
4940     EL_QUICKSAND_FILLING,               -1, -1
4941   },
4942 #else
4943   {
4944     Xsand_sandstone_1,                  FALSE,  FALSE,
4945     EL_QUICKSAND_FULL,                  -1, -1
4946   },
4947   {
4948     Xsand_sandstone_2,                  FALSE,  FALSE,
4949     EL_QUICKSAND_FULL,                  -1, -1
4950   },
4951   {
4952     Xsand_sandstone_3,                  FALSE,  FALSE,
4953     EL_QUICKSAND_FULL,                  -1, -1
4954   },
4955   {
4956     Xsand_sandstone_4,                  FALSE,  FALSE,
4957     EL_QUICKSAND_FULL,                  -1, -1
4958   },
4959 #endif
4960   {
4961     Xplant,                             TRUE,   FALSE,
4962     EL_EMC_PLANT,                       -1, -1
4963   },
4964   {
4965     Yplant,                             FALSE,  FALSE,
4966     EL_EMC_PLANT,                       -1, -1
4967   },
4968   {
4969     Xlenses,                            TRUE,   FALSE,
4970     EL_EMC_LENSES,                      -1, -1
4971   },
4972   {
4973     Xmagnify,                           TRUE,   FALSE,
4974     EL_EMC_MAGNIFIER,                   -1, -1
4975   },
4976   {
4977     Xdripper,                           TRUE,   FALSE,
4978     EL_EMC_DRIPPER,                     -1, -1
4979   },
4980   {
4981     XdripperB,                          FALSE,  FALSE,
4982     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
4983   },
4984   {
4985     Xfake_blank,                        TRUE,   FALSE,
4986     EL_INVISIBLE_WALL,                  -1, -1
4987   },
4988   {
4989     Xfake_blankB,                       FALSE,  FALSE,
4990     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
4991   },
4992   {
4993     Xfake_grass,                        TRUE,   FALSE,
4994     EL_EMC_FAKE_GRASS,                  -1, -1
4995   },
4996   {
4997     Xfake_grassB,                       FALSE,  FALSE,
4998     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
4999   },
5000   {
5001     Xfake_door_1,                       TRUE,   FALSE,
5002     EL_EM_GATE_1_GRAY,                  -1, -1
5003   },
5004   {
5005     Xfake_door_2,                       TRUE,   FALSE,
5006     EL_EM_GATE_2_GRAY,                  -1, -1
5007   },
5008   {
5009     Xfake_door_3,                       TRUE,   FALSE,
5010     EL_EM_GATE_3_GRAY,                  -1, -1
5011   },
5012   {
5013     Xfake_door_4,                       TRUE,   FALSE,
5014     EL_EM_GATE_4_GRAY,                  -1, -1
5015   },
5016   {
5017     Xfake_door_5,                       TRUE,   FALSE,
5018     EL_EMC_GATE_5_GRAY,                 -1, -1
5019   },
5020   {
5021     Xfake_door_6,                       TRUE,   FALSE,
5022     EL_EMC_GATE_6_GRAY,                 -1, -1
5023   },
5024   {
5025     Xfake_door_7,                       TRUE,   FALSE,
5026     EL_EMC_GATE_7_GRAY,                 -1, -1
5027   },
5028   {
5029     Xfake_door_8,                       TRUE,   FALSE,
5030     EL_EMC_GATE_8_GRAY,                 -1, -1
5031   },
5032   {
5033     Xfake_acid_1,                       TRUE,   FALSE,
5034     EL_EMC_FAKE_ACID,                   -1, -1
5035   },
5036   {
5037     Xfake_acid_2,                       FALSE,  FALSE,
5038     EL_EMC_FAKE_ACID,                   -1, -1
5039   },
5040   {
5041     Xfake_acid_3,                       FALSE,  FALSE,
5042     EL_EMC_FAKE_ACID,                   -1, -1
5043   },
5044   {
5045     Xfake_acid_4,                       FALSE,  FALSE,
5046     EL_EMC_FAKE_ACID,                   -1, -1
5047   },
5048   {
5049     Xfake_acid_5,                       FALSE,  FALSE,
5050     EL_EMC_FAKE_ACID,                   -1, -1
5051   },
5052   {
5053     Xfake_acid_6,                       FALSE,  FALSE,
5054     EL_EMC_FAKE_ACID,                   -1, -1
5055   },
5056   {
5057     Xfake_acid_7,                       FALSE,  FALSE,
5058     EL_EMC_FAKE_ACID,                   -1, -1
5059   },
5060   {
5061     Xfake_acid_8,                       FALSE,  FALSE,
5062     EL_EMC_FAKE_ACID,                   -1, -1
5063   },
5064   {
5065     Xsteel_1,                           TRUE,   FALSE,
5066     EL_STEELWALL,                       -1, -1
5067   },
5068   {
5069     Xsteel_2,                           TRUE,   FALSE,
5070     EL_EMC_STEELWALL_2,                 -1, -1
5071   },
5072   {
5073     Xsteel_3,                           TRUE,   FALSE,
5074     EL_EMC_STEELWALL_3,                 -1, -1
5075   },
5076   {
5077     Xsteel_4,                           TRUE,   FALSE,
5078     EL_EMC_STEELWALL_4,                 -1, -1
5079   },
5080   {
5081     Xwall_1,                            TRUE,   FALSE,
5082     EL_WALL,                            -1, -1
5083   },
5084   {
5085     Xwall_2,                            TRUE,   FALSE,
5086     EL_EMC_WALL_14,                     -1, -1
5087   },
5088   {
5089     Xwall_3,                            TRUE,   FALSE,
5090     EL_EMC_WALL_15,                     -1, -1
5091   },
5092   {
5093     Xwall_4,                            TRUE,   FALSE,
5094     EL_EMC_WALL_16,                     -1, -1
5095   },
5096   {
5097     Xround_wall_1,                      TRUE,   FALSE,
5098     EL_WALL_SLIPPERY,                   -1, -1
5099   },
5100   {
5101     Xround_wall_2,                      TRUE,   FALSE,
5102     EL_EMC_WALL_SLIPPERY_2,             -1, -1
5103   },
5104   {
5105     Xround_wall_3,                      TRUE,   FALSE,
5106     EL_EMC_WALL_SLIPPERY_3,             -1, -1
5107   },
5108   {
5109     Xround_wall_4,                      TRUE,   FALSE,
5110     EL_EMC_WALL_SLIPPERY_4,             -1, -1
5111   },
5112   {
5113     Xdecor_1,                           TRUE,   FALSE,
5114     EL_EMC_WALL_8,                      -1, -1
5115   },
5116   {
5117     Xdecor_2,                           TRUE,   FALSE,
5118     EL_EMC_WALL_6,                      -1, -1
5119   },
5120   {
5121     Xdecor_3,                           TRUE,   FALSE,
5122     EL_EMC_WALL_4,                      -1, -1
5123   },
5124   {
5125     Xdecor_4,                           TRUE,   FALSE,
5126     EL_EMC_WALL_7,                      -1, -1
5127   },
5128   {
5129     Xdecor_5,                           TRUE,   FALSE,
5130     EL_EMC_WALL_5,                      -1, -1
5131   },
5132   {
5133     Xdecor_6,                           TRUE,   FALSE,
5134     EL_EMC_WALL_9,                      -1, -1
5135   },
5136   {
5137     Xdecor_7,                           TRUE,   FALSE,
5138     EL_EMC_WALL_10,                     -1, -1
5139   },
5140   {
5141     Xdecor_8,                           TRUE,   FALSE,
5142     EL_EMC_WALL_1,                      -1, -1
5143   },
5144   {
5145     Xdecor_9,                           TRUE,   FALSE,
5146     EL_EMC_WALL_2,                      -1, -1
5147   },
5148   {
5149     Xdecor_10,                          TRUE,   FALSE,
5150     EL_EMC_WALL_3,                      -1, -1
5151   },
5152   {
5153     Xdecor_11,                          TRUE,   FALSE,
5154     EL_EMC_WALL_11,                     -1, -1
5155   },
5156   {
5157     Xdecor_12,                          TRUE,   FALSE,
5158     EL_EMC_WALL_12,                     -1, -1
5159   },
5160   {
5161     Xalpha_0,                           TRUE,   FALSE,
5162     EL_CHAR('0'),                       -1, -1
5163   },
5164   {
5165     Xalpha_1,                           TRUE,   FALSE,
5166     EL_CHAR('1'),                       -1, -1
5167   },
5168   {
5169     Xalpha_2,                           TRUE,   FALSE,
5170     EL_CHAR('2'),                       -1, -1
5171   },
5172   {
5173     Xalpha_3,                           TRUE,   FALSE,
5174     EL_CHAR('3'),                       -1, -1
5175   },
5176   {
5177     Xalpha_4,                           TRUE,   FALSE,
5178     EL_CHAR('4'),                       -1, -1
5179   },
5180   {
5181     Xalpha_5,                           TRUE,   FALSE,
5182     EL_CHAR('5'),                       -1, -1
5183   },
5184   {
5185     Xalpha_6,                           TRUE,   FALSE,
5186     EL_CHAR('6'),                       -1, -1
5187   },
5188   {
5189     Xalpha_7,                           TRUE,   FALSE,
5190     EL_CHAR('7'),                       -1, -1
5191   },
5192   {
5193     Xalpha_8,                           TRUE,   FALSE,
5194     EL_CHAR('8'),                       -1, -1
5195   },
5196   {
5197     Xalpha_9,                           TRUE,   FALSE,
5198     EL_CHAR('9'),                       -1, -1
5199   },
5200   {
5201     Xalpha_excla,                       TRUE,   FALSE,
5202     EL_CHAR('!'),                       -1, -1
5203   },
5204   {
5205     Xalpha_quote,                       TRUE,   FALSE,
5206     EL_CHAR('"'),                       -1, -1
5207   },
5208   {
5209     Xalpha_comma,                       TRUE,   FALSE,
5210     EL_CHAR(','),                       -1, -1
5211   },
5212   {
5213     Xalpha_minus,                       TRUE,   FALSE,
5214     EL_CHAR('-'),                       -1, -1
5215   },
5216   {
5217     Xalpha_perio,                       TRUE,   FALSE,
5218     EL_CHAR('.'),                       -1, -1
5219   },
5220   {
5221     Xalpha_colon,                       TRUE,   FALSE,
5222     EL_CHAR(':'),                       -1, -1
5223   },
5224   {
5225     Xalpha_quest,                       TRUE,   FALSE,
5226     EL_CHAR('?'),                       -1, -1
5227   },
5228   {
5229     Xalpha_a,                           TRUE,   FALSE,
5230     EL_CHAR('A'),                       -1, -1
5231   },
5232   {
5233     Xalpha_b,                           TRUE,   FALSE,
5234     EL_CHAR('B'),                       -1, -1
5235   },
5236   {
5237     Xalpha_c,                           TRUE,   FALSE,
5238     EL_CHAR('C'),                       -1, -1
5239   },
5240   {
5241     Xalpha_d,                           TRUE,   FALSE,
5242     EL_CHAR('D'),                       -1, -1
5243   },
5244   {
5245     Xalpha_e,                           TRUE,   FALSE,
5246     EL_CHAR('E'),                       -1, -1
5247   },
5248   {
5249     Xalpha_f,                           TRUE,   FALSE,
5250     EL_CHAR('F'),                       -1, -1
5251   },
5252   {
5253     Xalpha_g,                           TRUE,   FALSE,
5254     EL_CHAR('G'),                       -1, -1
5255   },
5256   {
5257     Xalpha_h,                           TRUE,   FALSE,
5258     EL_CHAR('H'),                       -1, -1
5259   },
5260   {
5261     Xalpha_i,                           TRUE,   FALSE,
5262     EL_CHAR('I'),                       -1, -1
5263   },
5264   {
5265     Xalpha_j,                           TRUE,   FALSE,
5266     EL_CHAR('J'),                       -1, -1
5267   },
5268   {
5269     Xalpha_k,                           TRUE,   FALSE,
5270     EL_CHAR('K'),                       -1, -1
5271   },
5272   {
5273     Xalpha_l,                           TRUE,   FALSE,
5274     EL_CHAR('L'),                       -1, -1
5275   },
5276   {
5277     Xalpha_m,                           TRUE,   FALSE,
5278     EL_CHAR('M'),                       -1, -1
5279   },
5280   {
5281     Xalpha_n,                           TRUE,   FALSE,
5282     EL_CHAR('N'),                       -1, -1
5283   },
5284   {
5285     Xalpha_o,                           TRUE,   FALSE,
5286     EL_CHAR('O'),                       -1, -1
5287   },
5288   {
5289     Xalpha_p,                           TRUE,   FALSE,
5290     EL_CHAR('P'),                       -1, -1
5291   },
5292   {
5293     Xalpha_q,                           TRUE,   FALSE,
5294     EL_CHAR('Q'),                       -1, -1
5295   },
5296   {
5297     Xalpha_r,                           TRUE,   FALSE,
5298     EL_CHAR('R'),                       -1, -1
5299   },
5300   {
5301     Xalpha_s,                           TRUE,   FALSE,
5302     EL_CHAR('S'),                       -1, -1
5303   },
5304   {
5305     Xalpha_t,                           TRUE,   FALSE,
5306     EL_CHAR('T'),                       -1, -1
5307   },
5308   {
5309     Xalpha_u,                           TRUE,   FALSE,
5310     EL_CHAR('U'),                       -1, -1
5311   },
5312   {
5313     Xalpha_v,                           TRUE,   FALSE,
5314     EL_CHAR('V'),                       -1, -1
5315   },
5316   {
5317     Xalpha_w,                           TRUE,   FALSE,
5318     EL_CHAR('W'),                       -1, -1
5319   },
5320   {
5321     Xalpha_x,                           TRUE,   FALSE,
5322     EL_CHAR('X'),                       -1, -1
5323   },
5324   {
5325     Xalpha_y,                           TRUE,   FALSE,
5326     EL_CHAR('Y'),                       -1, -1
5327   },
5328   {
5329     Xalpha_z,                           TRUE,   FALSE,
5330     EL_CHAR('Z'),                       -1, -1
5331   },
5332   {
5333     Xalpha_arrow_e,                     TRUE,   FALSE,
5334     EL_CHAR('>'),                       -1, -1
5335   },
5336   {
5337     Xalpha_arrow_w,                     TRUE,   FALSE,
5338     EL_CHAR('<'),                       -1, -1
5339   },
5340   {
5341     Xalpha_copyr,                       TRUE,   FALSE,
5342     EL_CHAR('©'),                       -1, -1
5343   },
5344
5345   {
5346     Xboom_bug,                          FALSE,  FALSE,
5347     EL_BUG,                             ACTION_EXPLODING, -1
5348   },
5349   {
5350     Xboom_bomb,                         FALSE,  FALSE,
5351     EL_BOMB,                            ACTION_EXPLODING, -1
5352   },
5353   {
5354     Xboom_android,                      FALSE,  FALSE,
5355     EL_EMC_ANDROID,                     ACTION_OTHER, -1
5356   },
5357   {
5358     Xboom_1,                            FALSE,  FALSE,
5359     EL_DEFAULT,                         ACTION_EXPLODING, -1
5360   },
5361   {
5362     Xboom_2,                            FALSE,  FALSE,
5363     EL_DEFAULT,                         ACTION_EXPLODING, -1
5364   },
5365   {
5366     Znormal,                            FALSE,  FALSE,
5367     EL_EMPTY,                           -1, -1
5368   },
5369   {
5370     Zdynamite,                          FALSE,  FALSE,
5371     EL_EMPTY,                           -1, -1
5372   },
5373   {
5374     Zplayer,                            FALSE,  FALSE,
5375     EL_EMPTY,                           -1, -1
5376   },
5377   {
5378     ZBORDER,                            FALSE,  FALSE,
5379     EL_EMPTY,                           -1, -1
5380   },
5381
5382   {
5383     -1,                                 FALSE,  FALSE,
5384     -1,                                 -1, -1
5385   }
5386 };
5387
5388 static struct Mapping_EM_to_RND_player
5389 {
5390   int action_em;
5391   int player_nr;
5392
5393   int element_rnd;
5394   int action;
5395   int direction;
5396 }
5397 em_player_mapping_list[] =
5398 {
5399   {
5400     SPR_walk + 0,                       0,
5401     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
5402   },
5403   {
5404     SPR_walk + 1,                       0,
5405     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
5406   },
5407   {
5408     SPR_walk + 2,                       0,
5409     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
5410   },
5411   {
5412     SPR_walk + 3,                       0,
5413     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
5414   },
5415   {
5416     SPR_push + 0,                       0,
5417     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
5418   },
5419   {
5420     SPR_push + 1,                       0,
5421     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
5422   },
5423   {
5424     SPR_push + 2,                       0,
5425     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
5426   },
5427   {
5428     SPR_push + 3,                       0,
5429     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
5430   },
5431   {
5432     SPR_spray + 0,                      0,
5433     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
5434   },
5435   {
5436     SPR_spray + 1,                      0,
5437     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5438   },
5439   {
5440     SPR_spray + 2,                      0,
5441     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
5442   },
5443   {
5444     SPR_spray + 3,                      0,
5445     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
5446   },
5447   {
5448     SPR_walk + 0,                       1,
5449     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
5450   },
5451   {
5452     SPR_walk + 1,                       1,
5453     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
5454   },
5455   {
5456     SPR_walk + 2,                       1,
5457     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
5458   },
5459   {
5460     SPR_walk + 3,                       1,
5461     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
5462   },
5463   {
5464     SPR_push + 0,                       1,
5465     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
5466   },
5467   {
5468     SPR_push + 1,                       1,
5469     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
5470   },
5471   {
5472     SPR_push + 2,                       1,
5473     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
5474   },
5475   {
5476     SPR_push + 3,                       1,
5477     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
5478   },
5479   {
5480     SPR_spray + 0,                      1,
5481     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
5482   },
5483   {
5484     SPR_spray + 1,                      1,
5485     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5486   },
5487   {
5488     SPR_spray + 2,                      1,
5489     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
5490   },
5491   {
5492     SPR_spray + 3,                      1,
5493     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
5494   },
5495   {
5496     SPR_still,                          0,
5497     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
5498   },
5499   {
5500     SPR_still,                          1,
5501     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
5502   },
5503   {
5504     SPR_walk + 0,                       2,
5505     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
5506   },
5507   {
5508     SPR_walk + 1,                       2,
5509     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
5510   },
5511   {
5512     SPR_walk + 2,                       2,
5513     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
5514   },
5515   {
5516     SPR_walk + 3,                       2,
5517     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
5518   },
5519   {
5520     SPR_push + 0,                       2,
5521     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
5522   },
5523   {
5524     SPR_push + 1,                       2,
5525     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
5526   },
5527   {
5528     SPR_push + 2,                       2,
5529     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
5530   },
5531   {
5532     SPR_push + 3,                       2,
5533     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
5534   },
5535   {
5536     SPR_spray + 0,                      2,
5537     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
5538   },
5539   {
5540     SPR_spray + 1,                      2,
5541     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5542   },
5543   {
5544     SPR_spray + 2,                      2,
5545     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
5546   },
5547   {
5548     SPR_spray + 3,                      2,
5549     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
5550   },
5551   {
5552     SPR_walk + 0,                       3,
5553     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
5554   },
5555   {
5556     SPR_walk + 1,                       3,
5557     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
5558   },
5559   {
5560     SPR_walk + 2,                       3,
5561     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
5562   },
5563   {
5564     SPR_walk + 3,                       3,
5565     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
5566   },
5567   {
5568     SPR_push + 0,                       3,
5569     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
5570   },
5571   {
5572     SPR_push + 1,                       3,
5573     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
5574   },
5575   {
5576     SPR_push + 2,                       3,
5577     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
5578   },
5579   {
5580     SPR_push + 3,                       3,
5581     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
5582   },
5583   {
5584     SPR_spray + 0,                      3,
5585     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
5586   },
5587   {
5588     SPR_spray + 1,                      3,
5589     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
5590   },
5591   {
5592     SPR_spray + 2,                      3,
5593     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
5594   },
5595   {
5596     SPR_spray + 3,                      3,
5597     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
5598   },
5599   {
5600     SPR_still,                          2,
5601     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
5602   },
5603   {
5604     SPR_still,                          3,
5605     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
5606   },
5607
5608   {
5609     -1,                                 -1,
5610     -1,                                 -1, -1
5611   }
5612 };
5613
5614 int map_element_RND_to_EM(int element_rnd)
5615 {
5616   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
5617   static boolean mapping_initialized = FALSE;
5618
5619   if (!mapping_initialized)
5620   {
5621     int i;
5622
5623     /* return "Xalpha_quest" for all undefined elements in mapping array */
5624     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
5625       mapping_RND_to_EM[i] = Xalpha_quest;
5626
5627     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5628       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
5629         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
5630           em_object_mapping_list[i].element_em;
5631
5632     mapping_initialized = TRUE;
5633   }
5634
5635   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
5636     return mapping_RND_to_EM[element_rnd];
5637
5638   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
5639
5640   return EL_UNKNOWN;
5641 }
5642
5643 int map_element_EM_to_RND(int element_em)
5644 {
5645   static unsigned short mapping_EM_to_RND[TILE_MAX];
5646   static boolean mapping_initialized = FALSE;
5647
5648   if (!mapping_initialized)
5649   {
5650     int i;
5651
5652     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
5653     for (i = 0; i < TILE_MAX; i++)
5654       mapping_EM_to_RND[i] = EL_UNKNOWN;
5655
5656     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
5657       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
5658         em_object_mapping_list[i].element_rnd;
5659
5660     mapping_initialized = TRUE;
5661   }
5662
5663   if (element_em >= 0 && element_em < TILE_MAX)
5664     return mapping_EM_to_RND[element_em];
5665
5666   Error(ERR_WARN, "invalid EM level element %d", element_em);
5667
5668   return EL_UNKNOWN;
5669 }
5670
5671 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
5672 {
5673   struct LevelInfo_EM *level_em = level->native_em_level;
5674   struct LEVEL *lev = level_em->lev;
5675   int i, j;
5676
5677   for (i = 0; i < TILE_MAX; i++)
5678     lev->android_array[i] = Xblank;
5679
5680   for (i = 0; i < level->num_android_clone_elements; i++)
5681   {
5682     int element_rnd = level->android_clone_element[i];
5683     int element_em = map_element_RND_to_EM(element_rnd);
5684
5685     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
5686       if (em_object_mapping_list[j].element_rnd == element_rnd)
5687         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
5688   }
5689 }
5690
5691 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
5692 {
5693   struct LevelInfo_EM *level_em = level->native_em_level;
5694   struct LEVEL *lev = level_em->lev;
5695   int i, j;
5696
5697   level->num_android_clone_elements = 0;
5698
5699   for (i = 0; i < TILE_MAX; i++)
5700   {
5701     int element_em = lev->android_array[i];
5702     int element_rnd;
5703     boolean element_found = FALSE;
5704
5705     if (element_em == Xblank)
5706       continue;
5707
5708     element_rnd = map_element_EM_to_RND(element_em);
5709
5710     for (j = 0; j < level->num_android_clone_elements; j++)
5711       if (level->android_clone_element[j] == element_rnd)
5712         element_found = TRUE;
5713
5714     if (!element_found)
5715     {
5716       level->android_clone_element[level->num_android_clone_elements++] =
5717         element_rnd;
5718
5719       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
5720         break;
5721     }
5722   }
5723
5724   if (level->num_android_clone_elements == 0)
5725   {
5726     level->num_android_clone_elements = 1;
5727     level->android_clone_element[0] = EL_EMPTY;
5728   }
5729 }
5730
5731 int map_direction_RND_to_EM(int direction)
5732 {
5733   return (direction == MV_UP    ? 0 :
5734           direction == MV_RIGHT ? 1 :
5735           direction == MV_DOWN  ? 2 :
5736           direction == MV_LEFT  ? 3 :
5737           -1);
5738 }
5739
5740 int map_direction_EM_to_RND(int direction)
5741 {
5742   return (direction == 0 ? MV_UP    :
5743           direction == 1 ? MV_RIGHT :
5744           direction == 2 ? MV_DOWN  :
5745           direction == 3 ? MV_LEFT  :
5746           MV_NONE);
5747 }
5748
5749 int get_next_element(int element)
5750 {
5751   switch (element)
5752   {
5753     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
5754     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
5755     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
5756     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
5757     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
5758     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
5759     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
5760     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
5761     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
5762     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
5763     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
5764
5765     default:                            return element;
5766   }
5767 }
5768
5769 #if 0
5770 int el_act_dir2img(int element, int action, int direction)
5771 {
5772   element = GFX_ELEMENT(element);
5773
5774   if (direction == MV_NONE)
5775     return element_info[element].graphic[action];
5776
5777   direction = MV_DIR_TO_BIT(direction);
5778
5779   return element_info[element].direction_graphic[action][direction];
5780 }
5781 #else
5782 int el_act_dir2img(int element, int action, int direction)
5783 {
5784   element = GFX_ELEMENT(element);
5785   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5786
5787   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5788   return element_info[element].direction_graphic[action][direction];
5789 }
5790 #endif
5791
5792 #if 0
5793 static int el_act_dir2crm(int element, int action, int direction)
5794 {
5795   element = GFX_ELEMENT(element);
5796
5797   if (direction == MV_NONE)
5798     return element_info[element].crumbled[action];
5799
5800   direction = MV_DIR_TO_BIT(direction);
5801
5802   return element_info[element].direction_crumbled[action][direction];
5803 }
5804 #else
5805 static int el_act_dir2crm(int element, int action, int direction)
5806 {
5807   element = GFX_ELEMENT(element);
5808   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
5809
5810   /* direction_graphic[][] == graphic[] for undefined direction graphics */
5811   return element_info[element].direction_crumbled[action][direction];
5812 }
5813 #endif
5814
5815 int el_act2img(int element, int action)
5816 {
5817   element = GFX_ELEMENT(element);
5818
5819   return element_info[element].graphic[action];
5820 }
5821
5822 int el_act2crm(int element, int action)
5823 {
5824   element = GFX_ELEMENT(element);
5825
5826   return element_info[element].crumbled[action];
5827 }
5828
5829 int el_dir2img(int element, int direction)
5830 {
5831   element = GFX_ELEMENT(element);
5832
5833   return el_act_dir2img(element, ACTION_DEFAULT, direction);
5834 }
5835
5836 int el2baseimg(int element)
5837 {
5838   return element_info[element].graphic[ACTION_DEFAULT];
5839 }
5840
5841 int el2img(int element)
5842 {
5843   element = GFX_ELEMENT(element);
5844
5845   return element_info[element].graphic[ACTION_DEFAULT];
5846 }
5847
5848 int el2edimg(int element)
5849 {
5850   element = GFX_ELEMENT(element);
5851
5852   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
5853 }
5854
5855 int el2preimg(int element)
5856 {
5857   element = GFX_ELEMENT(element);
5858
5859   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
5860 }
5861
5862 int el2panelimg(int element)
5863 {
5864   element = GFX_ELEMENT(element);
5865
5866   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
5867 }
5868
5869 int font2baseimg(int font_nr)
5870 {
5871   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
5872 }
5873
5874 int getBeltNrFromBeltElement(int element)
5875 {
5876   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
5877           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
5878           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
5879 }
5880
5881 int getBeltNrFromBeltActiveElement(int element)
5882 {
5883   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
5884           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
5885           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
5886 }
5887
5888 int getBeltNrFromBeltSwitchElement(int element)
5889 {
5890   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
5891           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
5892           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
5893 }
5894
5895 int getBeltDirNrFromBeltElement(int element)
5896 {
5897   static int belt_base_element[4] =
5898   {
5899     EL_CONVEYOR_BELT_1_LEFT,
5900     EL_CONVEYOR_BELT_2_LEFT,
5901     EL_CONVEYOR_BELT_3_LEFT,
5902     EL_CONVEYOR_BELT_4_LEFT
5903   };
5904
5905   int belt_nr = getBeltNrFromBeltElement(element);
5906   int belt_dir_nr = element - belt_base_element[belt_nr];
5907
5908   return (belt_dir_nr % 3);
5909 }
5910
5911 int getBeltDirNrFromBeltSwitchElement(int element)
5912 {
5913   static int belt_base_element[4] =
5914   {
5915     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5916     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5917     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5918     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5919   };
5920
5921   int belt_nr = getBeltNrFromBeltSwitchElement(element);
5922   int belt_dir_nr = element - belt_base_element[belt_nr];
5923
5924   return (belt_dir_nr % 3);
5925 }
5926
5927 int getBeltDirFromBeltElement(int element)
5928 {
5929   static int belt_move_dir[3] =
5930   {
5931     MV_LEFT,
5932     MV_NONE,
5933     MV_RIGHT
5934   };
5935
5936   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
5937
5938   return belt_move_dir[belt_dir_nr];
5939 }
5940
5941 int getBeltDirFromBeltSwitchElement(int element)
5942 {
5943   static int belt_move_dir[3] =
5944   {
5945     MV_LEFT,
5946     MV_NONE,
5947     MV_RIGHT
5948   };
5949
5950   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
5951
5952   return belt_move_dir[belt_dir_nr];
5953 }
5954
5955 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5956 {
5957   static int belt_base_element[4] =
5958   {
5959     EL_CONVEYOR_BELT_1_LEFT,
5960     EL_CONVEYOR_BELT_2_LEFT,
5961     EL_CONVEYOR_BELT_3_LEFT,
5962     EL_CONVEYOR_BELT_4_LEFT
5963   };
5964
5965   return belt_base_element[belt_nr] + belt_dir_nr;
5966 }
5967
5968 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5969 {
5970   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5971
5972   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5973 }
5974
5975 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
5976 {
5977   static int belt_base_element[4] =
5978   {
5979     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
5980     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
5981     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
5982     EL_CONVEYOR_BELT_4_SWITCH_LEFT
5983   };
5984
5985   return belt_base_element[belt_nr] + belt_dir_nr;
5986 }
5987
5988 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
5989 {
5990   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
5991
5992   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
5993 }
5994
5995 int getNumActivePlayers_EM()
5996 {
5997   int num_players = 0;
5998   int i;
5999
6000   if (!tape.playing)
6001     return -1;
6002
6003   for (i = 0; i < MAX_PLAYERS; i++)
6004     if (tape.player_participates[i])
6005       num_players++;
6006
6007   return num_players;
6008 }
6009
6010 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6011 {
6012   int game_frame_delay_value;
6013
6014   game_frame_delay_value =
6015     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6016      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6017      GameFrameDelay);
6018
6019   if (tape.playing && tape.warp_forward && !tape.pausing)
6020     game_frame_delay_value = 0;
6021
6022   return game_frame_delay_value;
6023 }
6024
6025 unsigned int InitRND(long seed)
6026 {
6027   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6028     return InitEngineRandom_EM(seed);
6029   else
6030     return InitEngineRandom_RND(seed);
6031 }
6032
6033 #if 1
6034 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6035 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6036 #endif
6037
6038 inline static int get_effective_element_EM(int tile, int frame_em)
6039 {
6040   int element             = object_mapping[tile].element_rnd;
6041   int action              = object_mapping[tile].action;
6042   boolean is_backside     = object_mapping[tile].is_backside;
6043   boolean action_removing = (action == ACTION_DIGGING ||
6044                              action == ACTION_SNAPPING ||
6045                              action == ACTION_COLLECTING);
6046
6047   if (frame_em < 7)
6048   {
6049     switch (tile)
6050     {
6051       case Yacid_splash_eB:
6052       case Yacid_splash_wB:
6053         return (frame_em > 5 ? EL_EMPTY : element);
6054
6055       default:
6056         return element;
6057     }
6058   }
6059   else  /* frame_em == 7 */
6060   {
6061     switch (tile)
6062     {
6063       case Yacid_splash_eB:
6064       case Yacid_splash_wB:
6065         return EL_EMPTY;
6066
6067       case Yemerald_stone:
6068         return EL_EMERALD;
6069
6070       case Ydiamond_stone:
6071         return EL_ROCK;
6072
6073       case Xdrip_stretch:
6074       case Xdrip_stretchB:
6075       case Ydrip_s1:
6076       case Ydrip_s1B:
6077       case Xball_1B:
6078       case Xball_2:
6079       case Xball_2B:
6080       case Yball_eat:
6081       case Ykey_1_eat:
6082       case Ykey_2_eat:
6083       case Ykey_3_eat:
6084       case Ykey_4_eat:
6085       case Ykey_5_eat:
6086       case Ykey_6_eat:
6087       case Ykey_7_eat:
6088       case Ykey_8_eat:
6089       case Ylenses_eat:
6090       case Ymagnify_eat:
6091       case Ygrass_eat:
6092       case Ydirt_eat:
6093       case Xsand_stonein_1:
6094       case Xsand_stonein_2:
6095       case Xsand_stonein_3:
6096       case Xsand_stonein_4:
6097         return element;
6098
6099       default:
6100         return (is_backside || action_removing ? EL_EMPTY : element);
6101     }
6102   }
6103 }
6104
6105 inline static boolean check_linear_animation_EM(int tile)
6106 {
6107   switch (tile)
6108   {
6109     case Xsand_stonesand_1:
6110     case Xsand_stonesand_quickout_1:
6111     case Xsand_sandstone_1:
6112     case Xsand_stonein_1:
6113     case Xsand_stoneout_1:
6114     case Xboom_1:
6115     case Xdynamite_1:
6116     case Ybug_w_n:
6117     case Ybug_n_e:
6118     case Ybug_e_s:
6119     case Ybug_s_w:
6120     case Ybug_e_n:
6121     case Ybug_s_e:
6122     case Ybug_w_s:
6123     case Ybug_n_w:
6124     case Ytank_w_n:
6125     case Ytank_n_e:
6126     case Ytank_e_s:
6127     case Ytank_s_w:
6128     case Ytank_e_n:
6129     case Ytank_s_e:
6130     case Ytank_w_s:
6131     case Ytank_n_w:
6132       return TRUE;
6133   }
6134
6135   return FALSE;
6136 }
6137
6138 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6139                                             boolean has_crumbled_graphics,
6140                                             int crumbled, int sync_frame)
6141 {
6142   /* if element can be crumbled, but certain action graphics are just empty
6143      space (like instantly snapping sand to empty space in 1 frame), do not
6144      treat these empty space graphics as crumbled graphics in EMC engine */
6145   if (crumbled == IMG_EMPTY_SPACE)
6146     has_crumbled_graphics = FALSE;
6147
6148   if (has_crumbled_graphics)
6149   {
6150     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6151     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6152                                            g_crumbled->anim_delay,
6153                                            g_crumbled->anim_mode,
6154                                            g_crumbled->anim_start_frame,
6155                                            sync_frame);
6156
6157     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6158                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6159
6160     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6161
6162     g_em->has_crumbled_graphics = TRUE;
6163   }
6164   else
6165   {
6166     g_em->crumbled_bitmap = NULL;
6167     g_em->crumbled_src_x = 0;
6168     g_em->crumbled_src_y = 0;
6169     g_em->crumbled_border_size = 0;
6170
6171     g_em->has_crumbled_graphics = FALSE;
6172   }
6173 }
6174
6175 void ResetGfxAnimation_EM(int x, int y, int tile)
6176 {
6177   GfxFrame[x][y] = 0;
6178 }
6179
6180 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6181                         int tile, int frame_em, int x, int y)
6182 {
6183   int action = object_mapping[tile].action;
6184 #if 1
6185   int direction = object_mapping[tile].direction;
6186   int effective_element = get_effective_element_EM(tile, frame_em);
6187   int graphic = (direction == MV_NONE ?
6188                  el_act2img(effective_element, action) :
6189                  el_act_dir2img(effective_element, action, direction));
6190   struct GraphicInfo *g = &graphic_info[graphic];
6191   int sync_frame;
6192 #endif
6193   boolean action_removing = (action == ACTION_DIGGING ||
6194                              action == ACTION_SNAPPING ||
6195                              action == ACTION_COLLECTING);
6196   boolean action_moving   = (action == ACTION_FALLING ||
6197                              action == ACTION_MOVING ||
6198                              action == ACTION_PUSHING ||
6199                              action == ACTION_EATING ||
6200                              action == ACTION_FILLING ||
6201                              action == ACTION_EMPTYING);
6202   boolean action_falling  = (action == ACTION_FALLING ||
6203                              action == ACTION_FILLING ||
6204                              action == ACTION_EMPTYING);
6205
6206 #if 0
6207   if (tile == Xsand_stonesand_1 ||
6208       tile == Xsand_stonesand_2 ||
6209       tile == Xsand_stonesand_3 ||
6210       tile == Xsand_stonesand_4)
6211     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6212 #endif
6213
6214 #if 1
6215   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6216   {
6217     GfxFrame[x][y] = 0;
6218
6219     // printf("::: resetting... [%d]\n", tile);
6220   }
6221 #else
6222   if (action_removing || check_linear_animation_EM(tile))
6223   {
6224     GfxFrame[x][y] = frame_em;
6225
6226     // printf("::: resetting... [%d]\n", tile);
6227   }
6228 #endif
6229   else if (action_moving)
6230   {
6231     boolean is_backside = object_mapping[tile].is_backside;
6232
6233     if (is_backside)
6234     {
6235       int direction = object_mapping[tile].direction;
6236       int move_dir = (action_falling ? MV_DOWN : direction);
6237
6238       GfxFrame[x][y]++;
6239
6240       if (move_dir == MV_LEFT)
6241         GfxFrame[x - 1][y] = GfxFrame[x][y];
6242       else if (move_dir == MV_RIGHT)
6243         GfxFrame[x + 1][y] = GfxFrame[x][y];
6244       else if (move_dir == MV_UP)
6245         GfxFrame[x][y - 1] = GfxFrame[x][y];
6246       else if (move_dir == MV_DOWN)
6247         GfxFrame[x][y + 1] = GfxFrame[x][y];
6248     }
6249   }
6250   else
6251   {
6252     GfxFrame[x][y]++;
6253
6254     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
6255     if (tile == Xsand_stonesand_quickout_1 ||
6256         tile == Xsand_stonesand_quickout_2)
6257       GfxFrame[x][y]++;
6258   }
6259
6260 #if 0
6261   if (tile == Xsand_stonesand_1 ||
6262       tile == Xsand_stonesand_2 ||
6263       tile == Xsand_stonesand_3 ||
6264       tile == Xsand_stonesand_4)
6265     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
6266 #endif
6267
6268 #if 1
6269   if (graphic_info[graphic].anim_global_sync)
6270     sync_frame = FrameCounter;
6271   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6272     sync_frame = GfxFrame[x][y];
6273   else
6274     sync_frame = 0;     /* playfield border (pseudo steel) */
6275
6276   SetRandomAnimationValue(x, y);
6277
6278   int frame = getAnimationFrame(g->anim_frames,
6279                                 g->anim_delay,
6280                                 g->anim_mode,
6281                                 g->anim_start_frame,
6282                                 sync_frame);
6283
6284   g_em->unique_identifier =
6285     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
6286 #endif
6287 }
6288
6289 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
6290                                   int tile, int frame_em, int x, int y)
6291 {
6292   int action = object_mapping[tile].action;
6293   int direction = object_mapping[tile].direction;
6294   int effective_element = get_effective_element_EM(tile, frame_em);
6295   int graphic = (direction == MV_NONE ?
6296                  el_act2img(effective_element, action) :
6297                  el_act_dir2img(effective_element, action, direction));
6298   int crumbled = (direction == MV_NONE ?
6299                   el_act2crm(effective_element, action) :
6300                   el_act_dir2crm(effective_element, action, direction));
6301   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6302   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6303   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6304   struct GraphicInfo *g = &graphic_info[graphic];
6305 #if 0
6306   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6307 #endif
6308   int sync_frame;
6309
6310 #if 0
6311   if (frame_em == 0)    /* reset animation frame for certain elements */
6312   {
6313     if (check_linear_animation_EM(tile))
6314       GfxFrame[x][y] = 0;
6315   }
6316 #endif
6317
6318   if (graphic_info[graphic].anim_global_sync)
6319     sync_frame = FrameCounter;
6320   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
6321     sync_frame = GfxFrame[x][y];
6322   else
6323     sync_frame = 0;     /* playfield border (pseudo steel) */
6324
6325   SetRandomAnimationValue(x, y);
6326
6327   int frame = getAnimationFrame(g->anim_frames,
6328                                 g->anim_delay,
6329                                 g->anim_mode,
6330                                 g->anim_start_frame,
6331                                 sync_frame);
6332
6333   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6334                       &g_em->src_x, &g_em->src_y, FALSE);
6335
6336   /* (updating the "crumbled" graphic definitions is probably not really needed,
6337      as animations for crumbled graphics can't be longer than one EMC cycle) */
6338 #if 1
6339   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6340                            sync_frame);
6341
6342 #else
6343
6344   g_em->crumbled_bitmap = NULL;
6345   g_em->crumbled_src_x = 0;
6346   g_em->crumbled_src_y = 0;
6347
6348   g_em->has_crumbled_graphics = FALSE;
6349
6350   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6351   {
6352     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6353                                            g_crumbled->anim_delay,
6354                                            g_crumbled->anim_mode,
6355                                            g_crumbled->anim_start_frame,
6356                                            sync_frame);
6357
6358     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6359                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6360
6361     g_em->has_crumbled_graphics = TRUE;
6362   }
6363 #endif
6364 }
6365
6366 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
6367                                   int player_nr, int anim, int frame_em)
6368 {
6369   int element   = player_mapping[player_nr][anim].element_rnd;
6370   int action    = player_mapping[player_nr][anim].action;
6371   int direction = player_mapping[player_nr][anim].direction;
6372   int graphic = (direction == MV_NONE ?
6373                  el_act2img(element, action) :
6374                  el_act_dir2img(element, action, direction));
6375   struct GraphicInfo *g = &graphic_info[graphic];
6376   int sync_frame;
6377
6378   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
6379
6380   stored_player[player_nr].StepFrame = frame_em;
6381
6382   sync_frame = stored_player[player_nr].Frame;
6383
6384   int frame = getAnimationFrame(g->anim_frames,
6385                                 g->anim_delay,
6386                                 g->anim_mode,
6387                                 g->anim_start_frame,
6388                                 sync_frame);
6389
6390   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
6391                       &g_em->src_x, &g_em->src_y, FALSE);
6392
6393 #if 0
6394   printf("::: %d: %d, %d [%d]\n",
6395          player_nr,
6396          stored_player[player_nr].Frame,
6397          stored_player[player_nr].StepFrame,
6398          FrameCounter);
6399 #endif
6400 }
6401
6402 void InitGraphicInfo_EM(void)
6403 {
6404 #if 0
6405   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6406   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6407 #endif
6408   int i, j, p;
6409
6410 #if DEBUG_EM_GFX
6411   int num_em_gfx_errors = 0;
6412
6413   if (graphic_info_em_object[0][0].bitmap == NULL)
6414   {
6415     /* EM graphics not yet initialized in em_open_all() */
6416
6417     return;
6418   }
6419
6420   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
6421 #endif
6422
6423   /* always start with reliable default values */
6424   for (i = 0; i < TILE_MAX; i++)
6425   {
6426     object_mapping[i].element_rnd = EL_UNKNOWN;
6427     object_mapping[i].is_backside = FALSE;
6428     object_mapping[i].action = ACTION_DEFAULT;
6429     object_mapping[i].direction = MV_NONE;
6430   }
6431
6432   /* always start with reliable default values */
6433   for (p = 0; p < MAX_PLAYERS; p++)
6434   {
6435     for (i = 0; i < SPR_MAX; i++)
6436     {
6437       player_mapping[p][i].element_rnd = EL_UNKNOWN;
6438       player_mapping[p][i].action = ACTION_DEFAULT;
6439       player_mapping[p][i].direction = MV_NONE;
6440     }
6441   }
6442
6443   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6444   {
6445     int e = em_object_mapping_list[i].element_em;
6446
6447     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
6448     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
6449
6450     if (em_object_mapping_list[i].action != -1)
6451       object_mapping[e].action = em_object_mapping_list[i].action;
6452
6453     if (em_object_mapping_list[i].direction != -1)
6454       object_mapping[e].direction =
6455         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
6456   }
6457
6458   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
6459   {
6460     int a = em_player_mapping_list[i].action_em;
6461     int p = em_player_mapping_list[i].player_nr;
6462
6463     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
6464
6465     if (em_player_mapping_list[i].action != -1)
6466       player_mapping[p][a].action = em_player_mapping_list[i].action;
6467
6468     if (em_player_mapping_list[i].direction != -1)
6469       player_mapping[p][a].direction =
6470         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
6471   }
6472
6473   for (i = 0; i < TILE_MAX; i++)
6474   {
6475     int element = object_mapping[i].element_rnd;
6476     int action = object_mapping[i].action;
6477     int direction = object_mapping[i].direction;
6478     boolean is_backside = object_mapping[i].is_backside;
6479 #if 0
6480     boolean action_removing = (action == ACTION_DIGGING ||
6481                                action == ACTION_SNAPPING ||
6482                                action == ACTION_COLLECTING);
6483 #endif
6484     boolean action_exploding = ((action == ACTION_EXPLODING ||
6485                                  action == ACTION_SMASHED_BY_ROCK ||
6486                                  action == ACTION_SMASHED_BY_SPRING) &&
6487                                 element != EL_DIAMOND);
6488     boolean action_active = (action == ACTION_ACTIVE);
6489     boolean action_other = (action == ACTION_OTHER);
6490
6491     for (j = 0; j < 8; j++)
6492     {
6493 #if 1
6494       int effective_element = get_effective_element_EM(i, j);
6495 #else
6496       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
6497                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
6498                                j < 7 ? element :
6499                                i == Xdrip_stretch ? element :
6500                                i == Xdrip_stretchB ? element :
6501                                i == Ydrip_s1 ? element :
6502                                i == Ydrip_s1B ? element :
6503                                i == Xball_1B ? element :
6504                                i == Xball_2 ? element :
6505                                i == Xball_2B ? element :
6506                                i == Yball_eat ? element :
6507                                i == Ykey_1_eat ? element :
6508                                i == Ykey_2_eat ? element :
6509                                i == Ykey_3_eat ? element :
6510                                i == Ykey_4_eat ? element :
6511                                i == Ykey_5_eat ? element :
6512                                i == Ykey_6_eat ? element :
6513                                i == Ykey_7_eat ? element :
6514                                i == Ykey_8_eat ? element :
6515                                i == Ylenses_eat ? element :
6516                                i == Ymagnify_eat ? element :
6517                                i == Ygrass_eat ? element :
6518                                i == Ydirt_eat ? element :
6519                                i == Yemerald_stone ? EL_EMERALD :
6520                                i == Ydiamond_stone ? EL_ROCK :
6521                                i == Xsand_stonein_1 ? element :
6522                                i == Xsand_stonein_2 ? element :
6523                                i == Xsand_stonein_3 ? element :
6524                                i == Xsand_stonein_4 ? element :
6525                                is_backside ? EL_EMPTY :
6526                                action_removing ? EL_EMPTY :
6527                                element);
6528 #endif
6529       int effective_action = (j < 7 ? action :
6530                               i == Xdrip_stretch ? action :
6531                               i == Xdrip_stretchB ? action :
6532                               i == Ydrip_s1 ? action :
6533                               i == Ydrip_s1B ? action :
6534                               i == Xball_1B ? action :
6535                               i == Xball_2 ? action :
6536                               i == Xball_2B ? action :
6537                               i == Yball_eat ? action :
6538                               i == Ykey_1_eat ? action :
6539                               i == Ykey_2_eat ? action :
6540                               i == Ykey_3_eat ? action :
6541                               i == Ykey_4_eat ? action :
6542                               i == Ykey_5_eat ? action :
6543                               i == Ykey_6_eat ? action :
6544                               i == Ykey_7_eat ? action :
6545                               i == Ykey_8_eat ? action :
6546                               i == Ylenses_eat ? action :
6547                               i == Ymagnify_eat ? action :
6548                               i == Ygrass_eat ? action :
6549                               i == Ydirt_eat ? action :
6550                               i == Xsand_stonein_1 ? action :
6551                               i == Xsand_stonein_2 ? action :
6552                               i == Xsand_stonein_3 ? action :
6553                               i == Xsand_stonein_4 ? action :
6554                               i == Xsand_stoneout_1 ? action :
6555                               i == Xsand_stoneout_2 ? action :
6556                               i == Xboom_android ? ACTION_EXPLODING :
6557                               action_exploding ? ACTION_EXPLODING :
6558                               action_active ? action :
6559                               action_other ? action :
6560                               ACTION_DEFAULT);
6561       int graphic = (el_act_dir2img(effective_element, effective_action,
6562                                     direction));
6563       int crumbled = (el_act_dir2crm(effective_element, effective_action,
6564                                      direction));
6565       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
6566       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
6567       boolean has_action_graphics = (graphic != base_graphic);
6568       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
6569       struct GraphicInfo *g = &graphic_info[graphic];
6570 #if 0
6571       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6572 #endif
6573       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6574       Bitmap *src_bitmap;
6575       int src_x, src_y;
6576       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
6577       boolean special_animation = (action != ACTION_DEFAULT &&
6578                                    g->anim_frames == 3 &&
6579                                    g->anim_delay == 2 &&
6580                                    g->anim_mode & ANIM_LINEAR);
6581       int sync_frame = (i == Xdrip_stretch ? 7 :
6582                         i == Xdrip_stretchB ? 7 :
6583                         i == Ydrip_s2 ? j + 8 :
6584                         i == Ydrip_s2B ? j + 8 :
6585                         i == Xacid_1 ? 0 :
6586                         i == Xacid_2 ? 10 :
6587                         i == Xacid_3 ? 20 :
6588                         i == Xacid_4 ? 30 :
6589                         i == Xacid_5 ? 40 :
6590                         i == Xacid_6 ? 50 :
6591                         i == Xacid_7 ? 60 :
6592                         i == Xacid_8 ? 70 :
6593                         i == Xfake_acid_1 ? 0 :
6594                         i == Xfake_acid_2 ? 10 :
6595                         i == Xfake_acid_3 ? 20 :
6596                         i == Xfake_acid_4 ? 30 :
6597                         i == Xfake_acid_5 ? 40 :
6598                         i == Xfake_acid_6 ? 50 :
6599                         i == Xfake_acid_7 ? 60 :
6600                         i == Xfake_acid_8 ? 70 :
6601                         i == Xball_2 ? 7 :
6602                         i == Xball_2B ? j + 8 :
6603                         i == Yball_eat ? j + 1 :
6604                         i == Ykey_1_eat ? j + 1 :
6605                         i == Ykey_2_eat ? j + 1 :
6606                         i == Ykey_3_eat ? j + 1 :
6607                         i == Ykey_4_eat ? j + 1 :
6608                         i == Ykey_5_eat ? j + 1 :
6609                         i == Ykey_6_eat ? j + 1 :
6610                         i == Ykey_7_eat ? j + 1 :
6611                         i == Ykey_8_eat ? j + 1 :
6612                         i == Ylenses_eat ? j + 1 :
6613                         i == Ymagnify_eat ? j + 1 :
6614                         i == Ygrass_eat ? j + 1 :
6615                         i == Ydirt_eat ? j + 1 :
6616                         i == Xamoeba_1 ? 0 :
6617                         i == Xamoeba_2 ? 1 :
6618                         i == Xamoeba_3 ? 2 :
6619                         i == Xamoeba_4 ? 3 :
6620                         i == Xamoeba_5 ? 0 :
6621                         i == Xamoeba_6 ? 1 :
6622                         i == Xamoeba_7 ? 2 :
6623                         i == Xamoeba_8 ? 3 :
6624                         i == Xexit_2 ? j + 8 :
6625                         i == Xexit_3 ? j + 16 :
6626                         i == Xdynamite_1 ? 0 :
6627                         i == Xdynamite_2 ? 8 :
6628                         i == Xdynamite_3 ? 16 :
6629                         i == Xdynamite_4 ? 24 :
6630                         i == Xsand_stonein_1 ? j + 1 :
6631                         i == Xsand_stonein_2 ? j + 9 :
6632                         i == Xsand_stonein_3 ? j + 17 :
6633                         i == Xsand_stonein_4 ? j + 25 :
6634                         i == Xsand_stoneout_1 && j == 0 ? 0 :
6635                         i == Xsand_stoneout_1 && j == 1 ? 0 :
6636                         i == Xsand_stoneout_1 && j == 2 ? 1 :
6637                         i == Xsand_stoneout_1 && j == 3 ? 2 :
6638                         i == Xsand_stoneout_1 && j == 4 ? 2 :
6639                         i == Xsand_stoneout_1 && j == 5 ? 3 :
6640                         i == Xsand_stoneout_1 && j == 6 ? 4 :
6641                         i == Xsand_stoneout_1 && j == 7 ? 4 :
6642                         i == Xsand_stoneout_2 && j == 0 ? 5 :
6643                         i == Xsand_stoneout_2 && j == 1 ? 6 :
6644                         i == Xsand_stoneout_2 && j == 2 ? 7 :
6645                         i == Xsand_stoneout_2 && j == 3 ? 8 :
6646                         i == Xsand_stoneout_2 && j == 4 ? 9 :
6647                         i == Xsand_stoneout_2 && j == 5 ? 11 :
6648                         i == Xsand_stoneout_2 && j == 6 ? 13 :
6649                         i == Xsand_stoneout_2 && j == 7 ? 15 :
6650                         i == Xboom_bug && j == 1 ? 2 :
6651                         i == Xboom_bug && j == 2 ? 2 :
6652                         i == Xboom_bug && j == 3 ? 4 :
6653                         i == Xboom_bug && j == 4 ? 4 :
6654                         i == Xboom_bug && j == 5 ? 2 :
6655                         i == Xboom_bug && j == 6 ? 2 :
6656                         i == Xboom_bug && j == 7 ? 0 :
6657                         i == Xboom_bomb && j == 1 ? 2 :
6658                         i == Xboom_bomb && j == 2 ? 2 :
6659                         i == Xboom_bomb && j == 3 ? 4 :
6660                         i == Xboom_bomb && j == 4 ? 4 :
6661                         i == Xboom_bomb && j == 5 ? 2 :
6662                         i == Xboom_bomb && j == 6 ? 2 :
6663                         i == Xboom_bomb && j == 7 ? 0 :
6664                         i == Xboom_android && j == 7 ? 6 :
6665                         i == Xboom_1 && j == 1 ? 2 :
6666                         i == Xboom_1 && j == 2 ? 2 :
6667                         i == Xboom_1 && j == 3 ? 4 :
6668                         i == Xboom_1 && j == 4 ? 4 :
6669                         i == Xboom_1 && j == 5 ? 6 :
6670                         i == Xboom_1 && j == 6 ? 6 :
6671                         i == Xboom_1 && j == 7 ? 8 :
6672                         i == Xboom_2 && j == 0 ? 8 :
6673                         i == Xboom_2 && j == 1 ? 8 :
6674                         i == Xboom_2 && j == 2 ? 10 :
6675                         i == Xboom_2 && j == 3 ? 10 :
6676                         i == Xboom_2 && j == 4 ? 10 :
6677                         i == Xboom_2 && j == 5 ? 12 :
6678                         i == Xboom_2 && j == 6 ? 12 :
6679                         i == Xboom_2 && j == 7 ? 12 :
6680                         special_animation && j == 4 ? 3 :
6681                         effective_action != action ? 0 :
6682                         j);
6683
6684 #if DEBUG_EM_GFX
6685       Bitmap *debug_bitmap = g_em->bitmap;
6686       int debug_src_x = g_em->src_x;
6687       int debug_src_y = g_em->src_y;
6688 #endif
6689
6690       int frame = getAnimationFrame(g->anim_frames,
6691                                     g->anim_delay,
6692                                     g->anim_mode,
6693                                     g->anim_start_frame,
6694                                     sync_frame);
6695
6696       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
6697                           g->double_movement && is_backside);
6698
6699       g_em->bitmap = src_bitmap;
6700       g_em->src_x = src_x;
6701       g_em->src_y = src_y;
6702       g_em->src_offset_x = 0;
6703       g_em->src_offset_y = 0;
6704       g_em->dst_offset_x = 0;
6705       g_em->dst_offset_y = 0;
6706       g_em->width  = TILEX;
6707       g_em->height = TILEY;
6708
6709       g_em->preserve_background = FALSE;
6710
6711 #if 1
6712       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
6713                                sync_frame);
6714
6715 #else
6716
6717       g_em->crumbled_bitmap = NULL;
6718       g_em->crumbled_src_x = 0;
6719       g_em->crumbled_src_y = 0;
6720       g_em->crumbled_border_size = 0;
6721
6722       g_em->has_crumbled_graphics = FALSE;
6723
6724 #if 0
6725       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
6726         printf("::: empty crumbled: %d [%s], %d, %d\n",
6727                effective_element, element_info[effective_element].token_name,
6728                effective_action, direction);
6729 #endif
6730
6731       /* if element can be crumbled, but certain action graphics are just empty
6732          space (like instantly snapping sand to empty space in 1 frame), do not
6733          treat these empty space graphics as crumbled graphics in EMC engine */
6734       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
6735       {
6736         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6737                                                g_crumbled->anim_delay,
6738                                                g_crumbled->anim_mode,
6739                                                g_crumbled->anim_start_frame,
6740                                                sync_frame);
6741
6742         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
6743
6744         g_em->has_crumbled_graphics = TRUE;
6745         g_em->crumbled_bitmap = src_bitmap;
6746         g_em->crumbled_src_x = src_x;
6747         g_em->crumbled_src_y = src_y;
6748         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6749
6750
6751 #if 0
6752         if (g_em == &graphic_info_em_object[207][0])
6753           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
6754                  graphic_info_em_object[207][0].crumbled_src_x,
6755                  graphic_info_em_object[207][0].crumbled_src_y,
6756
6757                  crumbled, frame, src_x, src_y,
6758
6759                  g->anim_frames,
6760                  g->anim_delay,
6761                  g->anim_mode,
6762                  g->anim_start_frame,
6763                  sync_frame,
6764                  gfx.anim_random_frame,
6765                  frame);
6766 #endif
6767
6768 #if 0
6769         printf("::: EMC tile %d is crumbled\n", i);
6770 #endif
6771       }
6772 #endif
6773
6774 #if 0
6775       if (element == EL_ROCK &&
6776           effective_action == ACTION_FILLING)
6777         printf("::: has_action_graphics == %d\n", has_action_graphics);
6778 #endif
6779
6780       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
6781                                    effective_action == ACTION_MOVING  ||
6782                                    effective_action == ACTION_PUSHING ||
6783                                    effective_action == ACTION_EATING)) ||
6784           (!has_action_graphics && (effective_action == ACTION_FILLING ||
6785                                     effective_action == ACTION_EMPTYING)))
6786       {
6787         int move_dir =
6788           (effective_action == ACTION_FALLING ||
6789            effective_action == ACTION_FILLING ||
6790            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
6791         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
6792         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
6793         int num_steps = (i == Ydrip_s1  ? 16 :
6794                          i == Ydrip_s1B ? 16 :
6795                          i == Ydrip_s2  ? 16 :
6796                          i == Ydrip_s2B ? 16 :
6797                          i == Xsand_stonein_1 ? 32 :
6798                          i == Xsand_stonein_2 ? 32 :
6799                          i == Xsand_stonein_3 ? 32 :
6800                          i == Xsand_stonein_4 ? 32 :
6801                          i == Xsand_stoneout_1 ? 16 :
6802                          i == Xsand_stoneout_2 ? 16 : 8);
6803         int cx = ABS(dx) * (TILEX / num_steps);
6804         int cy = ABS(dy) * (TILEY / num_steps);
6805         int step_frame = (i == Ydrip_s2         ? j + 8 :
6806                           i == Ydrip_s2B        ? j + 8 :
6807                           i == Xsand_stonein_2  ? j + 8 :
6808                           i == Xsand_stonein_3  ? j + 16 :
6809                           i == Xsand_stonein_4  ? j + 24 :
6810                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
6811         int step = (is_backside ? step_frame : num_steps - step_frame);
6812
6813         if (is_backside)        /* tile where movement starts */
6814         {
6815           if (dx < 0 || dy < 0)
6816           {
6817             g_em->src_offset_x = cx * step;
6818             g_em->src_offset_y = cy * step;
6819           }
6820           else
6821           {
6822             g_em->dst_offset_x = cx * step;
6823             g_em->dst_offset_y = cy * step;
6824           }
6825         }
6826         else                    /* tile where movement ends */
6827         {
6828           if (dx < 0 || dy < 0)
6829           {
6830             g_em->dst_offset_x = cx * step;
6831             g_em->dst_offset_y = cy * step;
6832           }
6833           else
6834           {
6835             g_em->src_offset_x = cx * step;
6836             g_em->src_offset_y = cy * step;
6837           }
6838         }
6839
6840         g_em->width  = TILEX - cx * step;
6841         g_em->height = TILEY - cy * step;
6842       }
6843
6844       /* create unique graphic identifier to decide if tile must be redrawn */
6845       /* bit 31 - 16 (16 bit): EM style graphic
6846          bit 15 - 12 ( 4 bit): EM style frame
6847          bit 11 -  6 ( 6 bit): graphic width
6848          bit  5 -  0 ( 6 bit): graphic height */
6849       g_em->unique_identifier =
6850         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
6851
6852 #if DEBUG_EM_GFX
6853
6854       /* skip check for EMC elements not contained in original EMC artwork */
6855       if (element == EL_EMC_FAKE_ACID)
6856         continue;
6857
6858       if (g_em->bitmap != debug_bitmap ||
6859           g_em->src_x != debug_src_x ||
6860           g_em->src_y != debug_src_y ||
6861           g_em->src_offset_x != 0 ||
6862           g_em->src_offset_y != 0 ||
6863           g_em->dst_offset_x != 0 ||
6864           g_em->dst_offset_y != 0 ||
6865           g_em->width != TILEX ||
6866           g_em->height != TILEY)
6867       {
6868         static int last_i = -1;
6869
6870         if (i != last_i)
6871         {
6872           printf("\n");
6873           last_i = i;
6874         }
6875
6876         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
6877                i, element, element_info[element].token_name,
6878                element_action_info[effective_action].suffix, direction);
6879
6880         if (element != effective_element)
6881           printf(" [%d ('%s')]",
6882                  effective_element,
6883                  element_info[effective_element].token_name);
6884
6885         printf("\n");
6886
6887         if (g_em->bitmap != debug_bitmap)
6888           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
6889                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
6890
6891         if (g_em->src_x != debug_src_x ||
6892             g_em->src_y != debug_src_y)
6893           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
6894                  j, (is_backside ? 'B' : 'F'),
6895                  g_em->src_x, g_em->src_y,
6896                  g_em->src_x / 32, g_em->src_y / 32,
6897                  debug_src_x, debug_src_y,
6898                  debug_src_x / 32, debug_src_y / 32);
6899
6900         if (g_em->src_offset_x != 0 ||
6901             g_em->src_offset_y != 0 ||
6902             g_em->dst_offset_x != 0 ||
6903             g_em->dst_offset_y != 0)
6904           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
6905                  j, is_backside,
6906                  g_em->src_offset_x, g_em->src_offset_y,
6907                  g_em->dst_offset_x, g_em->dst_offset_y);
6908
6909         if (g_em->width != TILEX ||
6910             g_em->height != TILEY)
6911           printf("    %d (%d): size %d,%d should be %d,%d\n",
6912                  j, is_backside,
6913                  g_em->width, g_em->height, TILEX, TILEY);
6914
6915         num_em_gfx_errors++;
6916       }
6917 #endif
6918
6919     }
6920   }
6921
6922   for (i = 0; i < TILE_MAX; i++)
6923   {
6924     for (j = 0; j < 8; j++)
6925     {
6926       int element = object_mapping[i].element_rnd;
6927       int action = object_mapping[i].action;
6928       int direction = object_mapping[i].direction;
6929       boolean is_backside = object_mapping[i].is_backside;
6930       int graphic_action  = el_act_dir2img(element, action, direction);
6931       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
6932
6933       if ((action == ACTION_SMASHED_BY_ROCK ||
6934            action == ACTION_SMASHED_BY_SPRING ||
6935            action == ACTION_EATING) &&
6936           graphic_action == graphic_default)
6937       {
6938         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
6939                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
6940                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
6941                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
6942                  Xspring);
6943
6944         /* no separate animation for "smashed by rock" -- use rock instead */
6945         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
6946         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
6947
6948         g_em->bitmap            = g_xx->bitmap;
6949         g_em->src_x             = g_xx->src_x;
6950         g_em->src_y             = g_xx->src_y;
6951         g_em->src_offset_x      = g_xx->src_offset_x;
6952         g_em->src_offset_y      = g_xx->src_offset_y;
6953         g_em->dst_offset_x      = g_xx->dst_offset_x;
6954         g_em->dst_offset_y      = g_xx->dst_offset_y;
6955         g_em->width             = g_xx->width;
6956         g_em->height            = g_xx->height;
6957         g_em->unique_identifier = g_xx->unique_identifier;
6958
6959         if (!is_backside)
6960           g_em->preserve_background = TRUE;
6961       }
6962     }
6963   }
6964
6965   for (p = 0; p < MAX_PLAYERS; p++)
6966   {
6967     for (i = 0; i < SPR_MAX; i++)
6968     {
6969       int element = player_mapping[p][i].element_rnd;
6970       int action = player_mapping[p][i].action;
6971       int direction = player_mapping[p][i].direction;
6972
6973       for (j = 0; j < 8; j++)
6974       {
6975         int effective_element = element;
6976         int effective_action = action;
6977         int graphic = (direction == MV_NONE ?
6978                        el_act2img(effective_element, effective_action) :
6979                        el_act_dir2img(effective_element, effective_action,
6980                                       direction));
6981         struct GraphicInfo *g = &graphic_info[graphic];
6982         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
6983         Bitmap *src_bitmap;
6984         int src_x, src_y;
6985         int sync_frame = j;
6986
6987 #if DEBUG_EM_GFX
6988         Bitmap *debug_bitmap = g_em->bitmap;
6989         int debug_src_x = g_em->src_x;
6990         int debug_src_y = g_em->src_y;
6991 #endif
6992
6993         int frame = getAnimationFrame(g->anim_frames,
6994                                       g->anim_delay,
6995                                       g->anim_mode,
6996                                       g->anim_start_frame,
6997                                       sync_frame);
6998
6999         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7000
7001         g_em->bitmap = src_bitmap;
7002         g_em->src_x = src_x;
7003         g_em->src_y = src_y;
7004         g_em->src_offset_x = 0;
7005         g_em->src_offset_y = 0;
7006         g_em->dst_offset_x = 0;
7007         g_em->dst_offset_y = 0;
7008         g_em->width  = TILEX;
7009         g_em->height = TILEY;
7010
7011 #if DEBUG_EM_GFX
7012
7013         /* skip check for EMC elements not contained in original EMC artwork */
7014         if (element == EL_PLAYER_3 ||
7015             element == EL_PLAYER_4)
7016           continue;
7017
7018         if (g_em->bitmap != debug_bitmap ||
7019             g_em->src_x != debug_src_x ||
7020             g_em->src_y != debug_src_y)
7021         {
7022           static int last_i = -1;
7023
7024           if (i != last_i)
7025           {
7026             printf("\n");
7027             last_i = i;
7028           }
7029
7030           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7031                  p, i, element, element_info[element].token_name,
7032                  element_action_info[effective_action].suffix, direction);
7033
7034           if (element != effective_element)
7035             printf(" [%d ('%s')]",
7036                    effective_element,
7037                    element_info[effective_element].token_name);
7038
7039           printf("\n");
7040
7041           if (g_em->bitmap != debug_bitmap)
7042             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
7043                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
7044
7045           if (g_em->src_x != debug_src_x ||
7046               g_em->src_y != debug_src_y)
7047             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7048                    j,
7049                    g_em->src_x, g_em->src_y,
7050                    g_em->src_x / 32, g_em->src_y / 32,
7051                    debug_src_x, debug_src_y,
7052                    debug_src_x / 32, debug_src_y / 32);
7053
7054           num_em_gfx_errors++;
7055         }
7056 #endif
7057
7058       }
7059     }
7060   }
7061
7062 #if DEBUG_EM_GFX
7063   printf("\n");
7064   printf("::: [%d errors found]\n", num_em_gfx_errors);
7065
7066   exit(0);
7067 #endif
7068 }
7069
7070 void PlayMenuSoundExt(int sound)
7071 {
7072   if (sound == SND_UNDEFINED)
7073     return;
7074
7075   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7076       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7077     return;
7078
7079   if (IS_LOOP_SOUND(sound))
7080     PlaySoundLoop(sound);
7081   else
7082     PlaySound(sound);
7083 }
7084
7085 void PlayMenuSound()
7086 {
7087   PlayMenuSoundExt(menu.sound[game_status]);
7088 }
7089
7090 void PlayMenuSoundStereo(int sound, int stereo_position)
7091 {
7092   if (sound == SND_UNDEFINED)
7093     return;
7094
7095   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7096       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7097     return;
7098
7099   if (IS_LOOP_SOUND(sound))
7100     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7101   else
7102     PlaySoundStereo(sound, stereo_position);
7103 }
7104
7105 void PlayMenuSoundIfLoopExt(int sound)
7106 {
7107   if (sound == SND_UNDEFINED)
7108     return;
7109
7110   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7111       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7112     return;
7113
7114   if (IS_LOOP_SOUND(sound))
7115     PlaySoundLoop(sound);
7116 }
7117
7118 void PlayMenuSoundIfLoop()
7119 {
7120   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7121 }
7122
7123 void PlayMenuMusicExt(int music)
7124 {
7125   if (music == MUS_UNDEFINED)
7126     return;
7127
7128   if (!setup.sound_music)
7129     return;
7130
7131   PlayMusic(music);
7132 }
7133
7134 void PlayMenuMusic()
7135 {
7136   PlayMenuMusicExt(menu.music[game_status]);
7137 }
7138
7139 void PlaySoundActivating()
7140 {
7141 #if 0
7142   PlaySound(SND_MENU_ITEM_ACTIVATING);
7143 #endif
7144 }
7145
7146 void PlaySoundSelecting()
7147 {
7148 #if 0
7149   PlaySound(SND_MENU_ITEM_SELECTING);
7150 #endif
7151 }
7152
7153 void ToggleFullscreenIfNeeded()
7154 {
7155   boolean change_fullscreen = (setup.fullscreen !=
7156                                video.fullscreen_enabled);
7157   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7158                                     !strEqual(setup.fullscreen_mode,
7159                                               video.fullscreen_mode_current));
7160
7161   if (!video.fullscreen_available)
7162     return;
7163
7164 #if 1
7165   if (change_fullscreen || change_fullscreen_mode)
7166 #else
7167   if (setup.fullscreen != video.fullscreen_enabled ||
7168       setup.fullscreen_mode != video.fullscreen_mode_current)
7169 #endif
7170   {
7171     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7172
7173     /* save backbuffer content which gets lost when toggling fullscreen mode */
7174     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7175
7176 #if 1
7177     if (change_fullscreen_mode)
7178 #else
7179     if (setup.fullscreen && video.fullscreen_enabled)
7180 #endif
7181     {
7182       /* keep fullscreen, but change fullscreen mode (screen resolution) */
7183 #if 1
7184       /* (this is now set in sdl.c) */
7185 #else
7186       video.fullscreen_mode_current = setup.fullscreen_mode;
7187 #endif
7188       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
7189     }
7190
7191     /* toggle fullscreen */
7192     ChangeVideoModeIfNeeded(setup.fullscreen);
7193
7194     setup.fullscreen = video.fullscreen_enabled;
7195
7196     /* restore backbuffer content from temporary backbuffer backup bitmap */
7197     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7198
7199     FreeBitmap(tmp_backbuffer);
7200
7201 #if 1
7202     /* update visible window/screen */
7203     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7204 #else
7205     redraw_mask = REDRAW_ALL;
7206 #endif
7207   }
7208 }