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