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