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