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