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