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