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