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