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