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