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