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