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