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