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