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