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