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