removed artifact from removed X11 support
[rocksndiamonds.git] / src / tools.c
1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
5 //                  Holger Schemel
6 //                  info@artsoft.org
7 //                  http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
9 // tools.c
10 // ============================================================================
11
12 #include <math.h>
13
14 #include "libgame/libgame.h"
15
16 #include "tools.h"
17 #include "init.h"
18 #include "game.h"
19 #include "events.h"
20 #include "cartoons.h"
21 #include "network.h"
22 #include "tape.h"
23 #include "screens.h"
24
25
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX    0
28
29 /* tool button identifiers */
30 #define TOOL_CTRL_ID_YES        0
31 #define TOOL_CTRL_ID_NO         1
32 #define TOOL_CTRL_ID_CONFIRM    2
33 #define TOOL_CTRL_ID_PLAYER_1   3
34 #define TOOL_CTRL_ID_PLAYER_2   4
35 #define TOOL_CTRL_ID_PLAYER_3   5
36 #define TOOL_CTRL_ID_PLAYER_4   6
37
38 #define NUM_TOOL_BUTTONS        7
39
40 /* constants for number of doors and door parts */
41 #define NUM_DOORS               2
42 #define NUM_PANELS              NUM_DOORS
43 // #define NUM_PANELS           0
44 #define MAX_PARTS_PER_DOOR      8
45 #define MAX_DOOR_PARTS          (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i)   ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
47
48
49 struct DoorPartOrderInfo
50 {
51   int nr;
52   int sort_priority;
53 };
54
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
56
57 struct DoorPartControlInfo
58 {
59   int door_token;
60   int graphic;
61   struct DoorPartPosInfo *pos;
62 };
63
64 static struct DoorPartControlInfo door_part_controls[] =
65 {
66   {
67     DOOR_1,
68     IMG_DOOR_1_GFX_PART_1,
69     &door_1.part_1
70   },
71   {
72     DOOR_1,
73     IMG_DOOR_1_GFX_PART_2,
74     &door_1.part_2
75   },
76   {
77     DOOR_1,
78     IMG_DOOR_1_GFX_PART_3,
79     &door_1.part_3
80   },
81   {
82     DOOR_1,
83     IMG_DOOR_1_GFX_PART_4,
84     &door_1.part_4
85   },
86   {
87     DOOR_1,
88     IMG_DOOR_1_GFX_PART_5,
89     &door_1.part_5
90   },
91   {
92     DOOR_1,
93     IMG_DOOR_1_GFX_PART_6,
94     &door_1.part_6
95   },
96   {
97     DOOR_1,
98     IMG_DOOR_1_GFX_PART_7,
99     &door_1.part_7
100   },
101   {
102     DOOR_1,
103     IMG_DOOR_1_GFX_PART_8,
104     &door_1.part_8
105   },
106
107   {
108     DOOR_2,
109     IMG_DOOR_2_GFX_PART_1,
110     &door_2.part_1
111   },
112   {
113     DOOR_2,
114     IMG_DOOR_2_GFX_PART_2,
115     &door_2.part_2
116   },
117   {
118     DOOR_2,
119     IMG_DOOR_2_GFX_PART_3,
120     &door_2.part_3
121   },
122   {
123     DOOR_2,
124     IMG_DOOR_2_GFX_PART_4,
125     &door_2.part_4
126   },
127   {
128     DOOR_2,
129     IMG_DOOR_2_GFX_PART_5,
130     &door_2.part_5
131   },
132   {
133     DOOR_2,
134     IMG_DOOR_2_GFX_PART_6,
135     &door_2.part_6
136   },
137   {
138     DOOR_2,
139     IMG_DOOR_2_GFX_PART_7,
140     &door_2.part_7
141   },
142   {
143     DOOR_2,
144     IMG_DOOR_2_GFX_PART_8,
145     &door_2.part_8
146   },
147
148   {
149     DOOR_1,
150     IMG_BACKGROUND_PANEL,
151     &door_1.panel
152   },
153   {
154     DOOR_2,
155     IMG_BACKGROUND_TAPE,
156     &door_2.panel
157   },
158
159   {
160     -1,
161     -1,
162     NULL
163   }
164 };
165
166
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
172
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
175
176 static char *print_if_not_empty(int element)
177 {
178   static char *s = NULL;
179   char *token_name = element_info[element].token_name;
180
181   if (s != NULL)
182     free(s);
183
184   s = checked_malloc(strlen(token_name) + 10 + 1);
185
186   if (element != EL_EMPTY)
187     sprintf(s, "%d\t['%s']", element, token_name);
188   else
189     sprintf(s, "%d", element);
190
191   return s;
192 }
193
194 void DumpTile(int x, int y)
195 {
196   int sx = SCREENX(x);
197   int sy = SCREENY(y);
198
199   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
200   {
201     x--;
202     y--;
203   }
204
205   printf_line("-", 79);
206   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207   printf_line("-", 79);
208
209   if (!IN_LEV_FIELD(x, y))
210   {
211     printf("(not in level field)\n");
212     printf("\n");
213
214     return;
215   }
216
217   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
218          element_info[Feld[x][y]].token_name);
219   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
220   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
221   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
222   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223   printf("  MovPos:      %d\n", MovPos[x][y]);
224   printf("  MovDir:      %d\n", MovDir[x][y]);
225   printf("  MovDelay:    %d\n", MovDelay[x][y]);
226   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
227   printf("  CustomValue: %d\n", CustomValue[x][y]);
228   printf("  GfxElement:  %d\n", GfxElement[x][y]);
229   printf("  GfxAction:   %d\n", GfxAction[x][y]);
230   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
231   printf("\n");
232 }
233
234 void SetDrawtoField(int mode)
235 {
236   if (mode == DRAW_FIELDBUFFER)
237   {
238     FX = 2 * TILEX_VAR;
239     FY = 2 * TILEY_VAR;
240     BX1 = -2;
241     BY1 = -2;
242     BX2 = SCR_FIELDX + 1;
243     BY2 = SCR_FIELDY + 1;
244
245     drawto_field = fieldbuffer;
246   }
247   else  /* DRAW_BACKBUFFER */
248   {
249     FX = SX;
250     FY = SY;
251     BX1 = 0;
252     BY1 = 0;
253     BX2 = SCR_FIELDX - 1;
254     BY2 = SCR_FIELDY - 1;
255
256     drawto_field = backbuffer;
257   }
258 }
259
260 static void RedrawPlayfield_RND()
261 {
262   if (game.envelope_active)
263     return;
264
265   DrawLevel(REDRAW_ALL);
266   DrawAllPlayers();
267 }
268
269 void RedrawPlayfield()
270 {
271   if (game_status != GAME_MODE_PLAYING)
272     return;
273
274   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275     RedrawPlayfield_EM(TRUE);
276   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277     RedrawPlayfield_SP(TRUE);
278   else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279     RedrawPlayfield_RND();
280
281   BlitScreenToBitmap(backbuffer);
282
283   BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
284              gfx.sx, gfx.sy);
285 }
286
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
288 {
289   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
290
291   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
292 }
293
294 void DrawMaskedBorder_FIELD()
295 {
296   if (global.border_status >= GAME_MODE_TITLE &&
297       global.border_status <= GAME_MODE_PLAYING &&
298       border.draw_masked[global.border_status])
299     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
300 }
301
302 void DrawMaskedBorder_DOOR_1()
303 {
304   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305       (global.border_status != GAME_MODE_EDITOR ||
306        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
308 }
309
310 void DrawMaskedBorder_DOOR_2()
311 {
312   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313       global.border_status != GAME_MODE_EDITOR)
314     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
315 }
316
317 void DrawMaskedBorder_DOOR_3()
318 {
319   /* currently not available */
320 }
321
322 void DrawMaskedBorder_ALL()
323 {
324   DrawMaskedBorder_FIELD();
325   DrawMaskedBorder_DOOR_1();
326   DrawMaskedBorder_DOOR_2();
327   DrawMaskedBorder_DOOR_3();
328 }
329
330 void DrawMaskedBorder(int redraw_mask)
331 {
332   /* never draw masked screen borders on borderless screens */
333   if (effectiveGameStatus() == GAME_MODE_LOADING ||
334       effectiveGameStatus() == GAME_MODE_TITLE)
335     return;
336
337   /* never draw masked screen borders when displaying request outside door */
338   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
339       global.use_envelope_request)
340     return;
341
342   if (redraw_mask & REDRAW_ALL)
343     DrawMaskedBorder_ALL();
344   else
345   {
346     if (redraw_mask & REDRAW_FIELD)
347       DrawMaskedBorder_FIELD();
348     if (redraw_mask & REDRAW_DOOR_1)
349       DrawMaskedBorder_DOOR_1();
350     if (redraw_mask & REDRAW_DOOR_2)
351       DrawMaskedBorder_DOOR_2();
352     if (redraw_mask & REDRAW_DOOR_3)
353       DrawMaskedBorder_DOOR_3();
354   }
355 }
356
357 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
358 {
359   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
360   int fx = FX, fy = FY;
361   int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
362   int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
363
364   int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
365   int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
366   int dx_var = dx * TILESIZE_VAR / TILESIZE;
367   int dy_var = dy * TILESIZE_VAR / TILESIZE;
368   int ffx, ffy;
369
370   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
371   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
372
373   if (EVEN(SCR_FIELDX))
374   {
375     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
376       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
377     else
378       fx += (dx_var > 0 ? TILEX_VAR : 0);
379   }
380   else
381   {
382     fx += dx_var;
383   }
384
385   if (EVEN(SCR_FIELDY))
386   {
387     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
388       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
389     else
390       fy += (dy_var > 0 ? TILEY_VAR : 0);
391   }
392   else
393   {
394     fy += dy_var;
395   }
396
397   if (full_lev_fieldx <= SCR_FIELDX)
398   {
399     if (EVEN(SCR_FIELDX))
400       fx = 2 * TILEX_VAR - (ODD(lev_fieldx)  ? TILEX_VAR / 2 : 0);
401     else
402       fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
403   }
404
405   if (full_lev_fieldy <= SCR_FIELDY)
406   {
407     if (EVEN(SCR_FIELDY))
408       fy = 2 * TILEY_VAR - (ODD(lev_fieldy)  ? TILEY_VAR / 2 : 0);
409     else
410       fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
411   }
412
413   if (border.draw_masked[GAME_MODE_PLAYING])
414   {
415     if (buffer != backbuffer)
416     {
417       /* copy playfield buffer to backbuffer to add masked border */
418       BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
419       DrawMaskedBorder(REDRAW_FIELD);
420     }
421
422     BlitBitmap(backbuffer, target_bitmap,
423                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
424                REAL_SX, REAL_SY);
425   }
426   else
427   {
428     BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
429   }
430 }
431
432 void BlitScreenToBitmap(Bitmap *target_bitmap)
433 {
434   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
435     BlitScreenToBitmap_EM(target_bitmap);
436   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
437     BlitScreenToBitmap_SP(target_bitmap);
438   else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
439     BlitScreenToBitmap_RND(target_bitmap);
440 }
441
442 void BackToFront()
443 {
444   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
445
446 #if 0
447   /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
448   /* (force full redraw) */
449   if (game_status == GAME_MODE_PLAYING)
450     redraw_mask |= REDRAW_FIELD;
451 #endif
452
453   if (redraw_mask == REDRAW_NONE)
454     return;
455
456 #if 0
457   printf("::: ");
458   if (redraw_mask & REDRAW_ALL)
459     printf("[REDRAW_ALL]");
460   if (redraw_mask & REDRAW_FIELD)
461     printf("[REDRAW_FIELD]");
462   if (redraw_mask & REDRAW_DOOR_1)
463     printf("[REDRAW_DOOR_1]");
464   if (redraw_mask & REDRAW_DOOR_2)
465     printf("[REDRAW_DOOR_2]");
466   if (redraw_mask & REDRAW_FROM_BACKBUFFER)
467     printf("[REDRAW_FROM_BACKBUFFER]");
468   printf(" [%d]\n", FrameCounter);
469 #endif
470
471   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
472   {
473     static boolean last_frame_skipped = FALSE;
474     boolean skip_even_when_not_scrolling = TRUE;
475     boolean just_scrolling = (ScreenMovDir != 0);
476     boolean verbose = FALSE;
477
478     if (global.fps_slowdown_factor > 1 &&
479         (FrameCounter % global.fps_slowdown_factor) &&
480         (just_scrolling || skip_even_when_not_scrolling))
481     {
482       redraw_mask &= ~REDRAW_MAIN;
483
484       last_frame_skipped = TRUE;
485
486       if (verbose)
487         printf("FRAME SKIPPED\n");
488     }
489     else
490     {
491       if (last_frame_skipped)
492         redraw_mask |= REDRAW_FIELD;
493
494       last_frame_skipped = FALSE;
495
496       if (verbose)
497         printf("frame not skipped\n");
498     }
499   }
500
501   /* synchronize X11 graphics at this point; if we would synchronize the
502      display immediately after the buffer switching (after the XFlush),
503      this could mean that we have to wait for the graphics to complete,
504      although we could go on doing calculations for the next frame */
505
506   /* SyncDisplay(); */
507
508   /* never draw masked border to backbuffer when using playfield buffer */
509   if (game_status != GAME_MODE_PLAYING ||
510       redraw_mask & REDRAW_FROM_BACKBUFFER ||
511       buffer == backbuffer)
512     DrawMaskedBorder(redraw_mask);
513   else
514     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
515
516   if (redraw_mask & REDRAW_ALL)
517   {
518     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
519
520     redraw_mask = REDRAW_NONE;
521   }
522
523   if (redraw_mask & REDRAW_FIELD)
524   {
525     if (game_status != GAME_MODE_PLAYING ||
526         redraw_mask & REDRAW_FROM_BACKBUFFER)
527     {
528       BlitBitmap(backbuffer, window,
529                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
530     }
531     else
532     {
533       BlitScreenToBitmap_RND(window);
534     }
535
536     redraw_mask &= ~REDRAW_MAIN;
537   }
538
539   if (redraw_mask & REDRAW_DOORS)
540   {
541     if (redraw_mask & REDRAW_DOOR_1)
542       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
543
544     if (redraw_mask & REDRAW_DOOR_2)
545       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
546
547     if (redraw_mask & REDRAW_DOOR_3)
548       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
549
550     redraw_mask &= ~REDRAW_DOORS;
551   }
552
553   if (redraw_mask & REDRAW_MICROLEVEL)
554   {
555     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
556                SX, SY + 10 * TILEY);
557
558     redraw_mask &= ~REDRAW_MICROLEVEL;
559   }
560
561   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
562   {
563     char text[100];
564     char info1[100];
565
566     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
567     if (!global.fps_slowdown)
568       info1[0] = '\0';
569
570     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
571
572     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
573   }
574
575   redraw_mask = REDRAW_NONE;
576 }
577
578 static void FadeCrossSaveBackbuffer()
579 {
580   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
581 }
582
583 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
584 {
585   static int fade_type_skip = FADE_TYPE_NONE;
586   void (*draw_border_function)(void) = NULL;
587   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
588   int x, y, width, height;
589   int fade_delay, post_delay;
590
591   if (fade_type == FADE_TYPE_FADE_OUT)
592   {
593     if (fade_type_skip != FADE_TYPE_NONE)
594     {
595       /* skip all fade operations until specified fade operation */
596       if (fade_type & fade_type_skip)
597         fade_type_skip = FADE_TYPE_NONE;
598
599       return;
600     }
601
602     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
603     {
604       FadeCrossSaveBackbuffer();
605
606       return;
607     }
608   }
609
610   redraw_mask |= fade_mask;
611
612   if (fade_type == FADE_TYPE_SKIP)
613   {
614     fade_type_skip = fade_mode;
615
616     return;
617   }
618
619   fade_delay = fading.fade_delay;
620   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
621
622   if (fade_type_skip != FADE_TYPE_NONE)
623   {
624     /* skip all fade operations until specified fade operation */
625     if (fade_type & fade_type_skip)
626       fade_type_skip = FADE_TYPE_NONE;
627
628     fade_delay = 0;
629   }
630
631   if (global.autoplay_leveldir)
632   {
633     return;
634   }
635
636   if (fade_mask == REDRAW_FIELD)
637   {
638     x = REAL_SX;
639     y = REAL_SY;
640     width  = FULL_SXSIZE;
641     height = FULL_SYSIZE;
642
643     if (border.draw_masked_when_fading)
644       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
645     else
646       DrawMaskedBorder_FIELD();                         /* draw once */
647   }
648   else          /* REDRAW_ALL */
649   {
650     x = 0;
651     y = 0;
652     width  = WIN_XSIZE;
653     height = WIN_YSIZE;
654   }
655
656   if (!setup.fade_screens ||
657       fade_delay == 0 ||
658       fading.fade_mode == FADE_MODE_NONE)
659   {
660     if (fade_mode == FADE_MODE_FADE_OUT)
661       return;
662
663     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
664
665     redraw_mask &= ~fade_mask;
666
667     return;
668   }
669
670   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
671                 draw_border_function);
672
673   redraw_mask &= ~fade_mask;
674 }
675
676 void FadeIn(int fade_mask)
677 {
678   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
679     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
680   else
681     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
682 }
683
684 void FadeOut(int fade_mask)
685 {
686   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
687     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
688   else
689     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
690
691   global.border_status = game_status;
692 }
693
694 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
695 {
696   static struct TitleFadingInfo fading_leave_stored;
697
698   if (set)
699     fading_leave_stored = fading_leave;
700   else
701     fading = fading_leave_stored;
702 }
703
704 void FadeSetEnterMenu()
705 {
706   fading = menu.enter_menu;
707
708   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
709 }
710
711 void FadeSetLeaveMenu()
712 {
713   fading = menu.leave_menu;
714
715   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
716 }
717
718 void FadeSetEnterScreen()
719 {
720   fading = menu.enter_screen[game_status];
721
722   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
723 }
724
725 void FadeSetNextScreen()
726 {
727   fading = menu.next_screen;
728
729   // (do not overwrite fade mode set by FadeSetEnterScreen)
730   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
731 }
732
733 void FadeSetLeaveScreen()
734 {
735   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
736 }
737
738 void FadeSetFromType(int type)
739 {
740   if (type & TYPE_ENTER_SCREEN)
741     FadeSetEnterScreen();
742   else if (type & TYPE_ENTER)
743     FadeSetEnterMenu();
744   else if (type & TYPE_LEAVE)
745     FadeSetLeaveMenu();
746 }
747
748 void FadeSetDisabled()
749 {
750   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
751
752   fading = fading_none;
753 }
754
755 void FadeSkipNextFadeIn()
756 {
757   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
758 }
759
760 void FadeSkipNextFadeOut()
761 {
762   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
763 }
764
765 void SetWindowBackgroundImageIfDefined(int graphic)
766 {
767   if (graphic_info[graphic].bitmap)
768     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
769 }
770
771 void SetMainBackgroundImageIfDefined(int graphic)
772 {
773   if (graphic_info[graphic].bitmap)
774     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
775 }
776
777 void SetDoorBackgroundImageIfDefined(int graphic)
778 {
779   if (graphic_info[graphic].bitmap)
780     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
781 }
782
783 void SetWindowBackgroundImage(int graphic)
784 {
785   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
786                             graphic_info[graphic].bitmap ?
787                             graphic_info[graphic].bitmap :
788                             graphic_info[IMG_BACKGROUND].bitmap);
789 }
790
791 void SetMainBackgroundImage(int graphic)
792 {
793   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
794                           graphic_info[graphic].bitmap ?
795                           graphic_info[graphic].bitmap :
796                           graphic_info[IMG_BACKGROUND].bitmap);
797 }
798
799 void SetDoorBackgroundImage(int graphic)
800 {
801   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
802                           graphic_info[graphic].bitmap ?
803                           graphic_info[graphic].bitmap :
804                           graphic_info[IMG_BACKGROUND].bitmap);
805 }
806
807 void SetPanelBackground()
808 {
809   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
810
811   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
812                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
813
814   SetDoorBackgroundBitmap(bitmap_db_panel);
815 }
816
817 void DrawBackground(int x, int y, int width, int height)
818 {
819   /* "drawto" might still point to playfield buffer here (hall of fame) */
820   ClearRectangleOnBackground(backbuffer, x, y, width, height);
821
822   if (IN_GFX_FIELD_FULL(x, y))
823     redraw_mask |= REDRAW_FIELD;
824   else if (IN_GFX_DOOR_1(x, y))
825     redraw_mask |= REDRAW_DOOR_1;
826   else if (IN_GFX_DOOR_2(x, y))
827     redraw_mask |= REDRAW_DOOR_2;
828   else if (IN_GFX_DOOR_3(x, y))
829     redraw_mask |= REDRAW_DOOR_3;
830 }
831
832 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
833 {
834   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
835
836   if (font->bitmap == NULL)
837     return;
838
839   DrawBackground(x, y, width, height);
840 }
841
842 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
843 {
844   struct GraphicInfo *g = &graphic_info[graphic];
845
846   if (g->bitmap == NULL)
847     return;
848
849   DrawBackground(x, y, width, height);
850 }
851
852 void ClearField()
853 {
854   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
855   /* (when entering hall of fame after playing) */
856   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
857
858   /* !!! maybe this should be done before clearing the background !!! */
859   if (game_status == GAME_MODE_PLAYING)
860   {
861     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
862     SetDrawtoField(DRAW_FIELDBUFFER);
863   }
864   else
865     SetDrawtoField(DRAW_BACKBUFFER);
866 }
867
868 void MarkTileDirty(int x, int y)
869 {
870   redraw_mask |= REDRAW_FIELD;
871 }
872
873 void SetBorderElement()
874 {
875   int x, y;
876
877   BorderElement = EL_EMPTY;
878
879   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
880   {
881     for (x = 0; x < lev_fieldx; x++)
882     {
883       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
884         BorderElement = EL_STEELWALL;
885
886       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
887         x = lev_fieldx - 2;
888     }
889   }
890 }
891
892 void FloodFillLevel(int from_x, int from_y, int fill_element,
893                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
894                     int max_fieldx, int max_fieldy)
895 {
896   int i,x,y;
897   int old_element;
898   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
899   static int safety = 0;
900
901   /* check if starting field still has the desired content */
902   if (field[from_x][from_y] == fill_element)
903     return;
904
905   safety++;
906
907   if (safety > max_fieldx * max_fieldy)
908     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
909
910   old_element = field[from_x][from_y];
911   field[from_x][from_y] = fill_element;
912
913   for (i = 0; i < 4; i++)
914   {
915     x = from_x + check[i][0];
916     y = from_y + check[i][1];
917
918     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
919       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
920   }
921
922   safety--;
923 }
924
925 void SetRandomAnimationValue(int x, int y)
926 {
927   gfx.anim_random_frame = GfxRandom[x][y];
928 }
929
930 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
931 {
932   /* animation synchronized with global frame counter, not move position */
933   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
934     sync_frame = FrameCounter;
935
936   return getAnimationFrame(graphic_info[graphic].anim_frames,
937                            graphic_info[graphic].anim_delay,
938                            graphic_info[graphic].anim_mode,
939                            graphic_info[graphic].anim_start_frame,
940                            sync_frame);
941 }
942
943 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
944                               Bitmap **bitmap, int *x, int *y,
945                               boolean get_backside)
946 {
947   struct GraphicInfo *g = &graphic_info[graphic];
948   Bitmap *src_bitmap = g->bitmap;
949   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
950   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
951   int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
952
953   // if no in-game graphics defined, always use standard graphic size
954   if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
955     tilesize = TILESIZE;
956
957   if (tilesize == gfx.standard_tile_size)
958     src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
959   else if (tilesize == game.tile_size)
960     src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
961   else
962     src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
963
964   if (g->offset_y == 0)         /* frames are ordered horizontally */
965   {
966     int max_width = g->anim_frames_per_line * g->width;
967     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
968
969     src_x = pos % max_width;
970     src_y = src_y % g->height + pos / max_width * g->height;
971   }
972   else if (g->offset_x == 0)    /* frames are ordered vertically */
973   {
974     int max_height = g->anim_frames_per_line * g->height;
975     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
976
977     src_x = src_x % g->width + pos / max_height * g->width;
978     src_y = pos % max_height;
979   }
980   else                          /* frames are ordered diagonally */
981   {
982     src_x = src_x + frame * g->offset_x;
983     src_y = src_y + frame * g->offset_y;
984   }
985
986   *bitmap = src_bitmap;
987   *x = src_x * tilesize / TILESIZE;
988   *y = src_y * tilesize / TILESIZE;
989 }
990
991 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
992                               int *x, int *y, boolean get_backside)
993 {
994   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
995                            get_backside);
996 }
997
998 void getSizedGraphicSource(int graphic, int frame, int tilesize,
999                            Bitmap **bitmap, int *x, int *y)
1000 {
1001   getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1002 }
1003
1004 void getFixedGraphicSource(int graphic, int frame,
1005                            Bitmap **bitmap, int *x, int *y)
1006 {
1007   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1008 }
1009
1010 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1011 {
1012   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1013 }
1014
1015 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1016                                 int *x, int *y, boolean get_backside)
1017 {
1018   struct GraphicInfo *g = &graphic_info[graphic];
1019   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1020   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1021
1022   if (TILESIZE_VAR != TILESIZE)
1023     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1024                                     get_backside);
1025
1026   *bitmap = g->bitmap;
1027
1028   if (g->offset_y == 0)         /* frames are ordered horizontally */
1029   {
1030     int max_width = g->anim_frames_per_line * g->width;
1031     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1032
1033     *x = pos % max_width;
1034     *y = src_y % g->height + pos / max_width * g->height;
1035   }
1036   else if (g->offset_x == 0)    /* frames are ordered vertically */
1037   {
1038     int max_height = g->anim_frames_per_line * g->height;
1039     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1040
1041     *x = src_x % g->width + pos / max_height * g->width;
1042     *y = pos % max_height;
1043   }
1044   else                          /* frames are ordered diagonally */
1045   {
1046     *x = src_x + frame * g->offset_x;
1047     *y = src_y + frame * g->offset_y;
1048   }
1049 }
1050
1051 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1052 {
1053   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1054 }
1055
1056 void DrawGraphic(int x, int y, int graphic, int frame)
1057 {
1058 #if DEBUG
1059   if (!IN_SCR_FIELD(x, y))
1060   {
1061     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1062     printf("DrawGraphic(): This should never happen!\n");
1063     return;
1064   }
1065 #endif
1066
1067   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1068                  frame);
1069
1070   MarkTileDirty(x, y);
1071 }
1072
1073 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1074 {
1075 #if DEBUG
1076   if (!IN_SCR_FIELD(x, y))
1077   {
1078     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1079     printf("DrawGraphic(): This should never happen!\n");
1080     return;
1081   }
1082 #endif
1083
1084   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1085                       frame);
1086   MarkTileDirty(x, y);
1087 }
1088
1089 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1090                     int frame)
1091 {
1092   Bitmap *src_bitmap;
1093   int src_x, src_y;
1094
1095   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1096
1097   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1098 }
1099
1100 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1101                          int frame)
1102 {
1103   Bitmap *src_bitmap;
1104   int src_x, src_y;
1105
1106   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1107   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1108 }
1109
1110 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1111 {
1112 #if DEBUG
1113   if (!IN_SCR_FIELD(x, y))
1114   {
1115     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1116     printf("DrawGraphicThruMask(): This should never happen!\n");
1117     return;
1118   }
1119 #endif
1120
1121   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1122                          graphic, frame);
1123
1124   MarkTileDirty(x, y);
1125 }
1126
1127 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1128 {
1129 #if DEBUG
1130   if (!IN_SCR_FIELD(x, y))
1131   {
1132     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1133     printf("DrawGraphicThruMask(): This should never happen!\n");
1134     return;
1135   }
1136 #endif
1137
1138   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1139                               graphic, frame);
1140   MarkTileDirty(x, y);
1141 }
1142
1143 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1144                             int frame)
1145 {
1146   Bitmap *src_bitmap;
1147   int src_x, src_y;
1148
1149   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1150
1151   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1152                    dst_x, dst_y);
1153 }
1154
1155 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1156                                  int graphic, int frame)
1157 {
1158   struct GraphicInfo *g = &graphic_info[graphic];
1159   Bitmap *src_bitmap;
1160   int src_x, src_y;
1161
1162   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1163
1164   BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1165                    dst_x, dst_y);
1166 }
1167
1168 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1169 {
1170   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1171                       frame, tilesize);
1172   MarkTileDirty(x / tilesize, y / tilesize);
1173 }
1174
1175 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1176                          int tilesize)
1177 {
1178   Bitmap *src_bitmap;
1179   int src_x, src_y;
1180
1181   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1182   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1183 }
1184
1185 void DrawMiniGraphic(int x, int y, int graphic)
1186 {
1187   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1188   MarkTileDirty(x / 2, y / 2);
1189 }
1190
1191 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1192 {
1193   Bitmap *src_bitmap;
1194   int src_x, src_y;
1195
1196   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1197   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1198 }
1199
1200 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1201                                             int graphic, int frame,
1202                                             int cut_mode, int mask_mode)
1203 {
1204   Bitmap *src_bitmap;
1205   int src_x, src_y;
1206   int dst_x, dst_y;
1207   int width = TILEX, height = TILEY;
1208   int cx = 0, cy = 0;
1209
1210   if (dx || dy)                 /* shifted graphic */
1211   {
1212     if (x < BX1)                /* object enters playfield from the left */
1213     {
1214       x = BX1;
1215       width = dx;
1216       cx = TILEX - dx;
1217       dx = 0;
1218     }
1219     else if (x > BX2)           /* object enters playfield from the right */
1220     {
1221       x = BX2;
1222       width = -dx;
1223       dx = TILEX + dx;
1224     }
1225     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1226     {
1227       width += dx;
1228       cx = -dx;
1229       dx = 0;
1230     }
1231     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1232       width -= dx;
1233     else if (dx)                /* general horizontal movement */
1234       MarkTileDirty(x + SIGN(dx), y);
1235
1236     if (y < BY1)                /* object enters playfield from the top */
1237     {
1238       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1239         return;
1240
1241       y = BY1;
1242       height = dy;
1243       cy = TILEY - dy;
1244       dy = 0;
1245     }
1246     else if (y > BY2)           /* object enters playfield from the bottom */
1247     {
1248       y = BY2;
1249       height = -dy;
1250       dy = TILEY + dy;
1251     }
1252     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1253     {
1254       height += dy;
1255       cy = -dy;
1256       dy = 0;
1257     }
1258     else if (dy > 0 && cut_mode == CUT_ABOVE)
1259     {
1260       if (y == BY2)             /* object completely above bottom border */
1261         return;
1262
1263       height = dy;
1264       cy = TILEY - dy;
1265       dy = TILEY;
1266       MarkTileDirty(x, y + 1);
1267     }                           /* object leaves playfield to the bottom */
1268     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1269       height -= dy;
1270     else if (dy)                /* general vertical movement */
1271       MarkTileDirty(x, y + SIGN(dy));
1272   }
1273
1274 #if DEBUG
1275   if (!IN_SCR_FIELD(x, y))
1276   {
1277     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1278     printf("DrawGraphicShifted(): This should never happen!\n");
1279     return;
1280   }
1281 #endif
1282
1283   width = width * TILESIZE_VAR / TILESIZE;
1284   height = height * TILESIZE_VAR / TILESIZE;
1285   cx = cx * TILESIZE_VAR / TILESIZE;
1286   cy = cy * TILESIZE_VAR / TILESIZE;
1287   dx = dx * TILESIZE_VAR / TILESIZE;
1288   dy = dy * TILESIZE_VAR / TILESIZE;
1289
1290   if (width > 0 && height > 0)
1291   {
1292     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1293
1294     src_x += cx;
1295     src_y += cy;
1296
1297     dst_x = FX + x * TILEX_VAR + dx;
1298     dst_y = FY + y * TILEY_VAR + dy;
1299
1300     if (mask_mode == USE_MASKING)
1301       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1302                        dst_x, dst_y);
1303     else
1304       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1305                  dst_x, dst_y);
1306
1307     MarkTileDirty(x, y);
1308   }
1309 }
1310
1311 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1312                                             int graphic, int frame,
1313                                             int cut_mode, int mask_mode)
1314 {
1315   Bitmap *src_bitmap;
1316   int src_x, src_y;
1317   int dst_x, dst_y;
1318   int width = TILEX_VAR, height = TILEY_VAR;
1319   int x1 = x;
1320   int y1 = y;
1321   int x2 = x + SIGN(dx);
1322   int y2 = y + SIGN(dy);
1323
1324   /* movement with two-tile animations must be sync'ed with movement position,
1325      not with current GfxFrame (which can be higher when using slow movement) */
1326   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1327   int anim_frames = graphic_info[graphic].anim_frames;
1328
1329   /* (we also need anim_delay here for movement animations with less frames) */
1330   int anim_delay = graphic_info[graphic].anim_delay;
1331   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1332
1333   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1334   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1335
1336   /* re-calculate animation frame for two-tile movement animation */
1337   frame = getGraphicAnimationFrame(graphic, sync_frame);
1338
1339   /* check if movement start graphic inside screen area and should be drawn */
1340   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1341   {
1342     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1343
1344     dst_x = FX + x1 * TILEX_VAR;
1345     dst_y = FY + y1 * TILEY_VAR;
1346
1347     if (mask_mode == USE_MASKING)
1348       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1349                        dst_x, dst_y);
1350     else
1351       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1352                  dst_x, dst_y);
1353
1354     MarkTileDirty(x1, y1);
1355   }
1356
1357   /* check if movement end graphic inside screen area and should be drawn */
1358   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1359   {
1360     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1361
1362     dst_x = FX + x2 * TILEX_VAR;
1363     dst_y = FY + y2 * TILEY_VAR;
1364
1365     if (mask_mode == USE_MASKING)
1366       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1367                        dst_x, dst_y);
1368     else
1369       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1370                  dst_x, dst_y);
1371
1372     MarkTileDirty(x2, y2);
1373   }
1374 }
1375
1376 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1377                                int graphic, int frame,
1378                                int cut_mode, int mask_mode)
1379 {
1380   if (graphic < 0)
1381   {
1382     DrawGraphic(x, y, graphic, frame);
1383
1384     return;
1385   }
1386
1387   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1388     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1389   else
1390     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1391 }
1392
1393 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1394                                 int frame, int cut_mode)
1395 {
1396   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1397 }
1398
1399 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1400                           int cut_mode, int mask_mode)
1401 {
1402   int lx = LEVELX(x), ly = LEVELY(y);
1403   int graphic;
1404   int frame;
1405
1406   if (IN_LEV_FIELD(lx, ly))
1407   {
1408     SetRandomAnimationValue(lx, ly);
1409
1410     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1411     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1412
1413     /* do not use double (EM style) movement graphic when not moving */
1414     if (graphic_info[graphic].double_movement && !dx && !dy)
1415     {
1416       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1417       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1418     }
1419   }
1420   else  /* border element */
1421   {
1422     graphic = el2img(element);
1423     frame = getGraphicAnimationFrame(graphic, -1);
1424   }
1425
1426   if (element == EL_EXPANDABLE_WALL)
1427   {
1428     boolean left_stopped = FALSE, right_stopped = FALSE;
1429
1430     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1431       left_stopped = TRUE;
1432     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1433       right_stopped = TRUE;
1434
1435     if (left_stopped && right_stopped)
1436       graphic = IMG_WALL;
1437     else if (left_stopped)
1438     {
1439       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1440       frame = graphic_info[graphic].anim_frames - 1;
1441     }
1442     else if (right_stopped)
1443     {
1444       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1445       frame = graphic_info[graphic].anim_frames - 1;
1446     }
1447   }
1448
1449   if (dx || dy)
1450     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1451   else if (mask_mode == USE_MASKING)
1452     DrawGraphicThruMask(x, y, graphic, frame);
1453   else
1454     DrawGraphic(x, y, graphic, frame);
1455 }
1456
1457 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1458                          int cut_mode, int mask_mode)
1459 {
1460   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1461     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1462                          cut_mode, mask_mode);
1463 }
1464
1465 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1466                               int cut_mode)
1467 {
1468   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1469 }
1470
1471 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1472                              int cut_mode)
1473 {
1474   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1475 }
1476
1477 void DrawLevelElementThruMask(int x, int y, int element)
1478 {
1479   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1480 }
1481
1482 void DrawLevelFieldThruMask(int x, int y)
1483 {
1484   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1485 }
1486
1487 /* !!! implementation of quicksand is totally broken !!! */
1488 #define IS_CRUMBLED_TILE(x, y, e)                                       \
1489         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
1490                              !IS_MOVING(x, y) ||                        \
1491                              (e) == EL_QUICKSAND_EMPTYING ||            \
1492                              (e) == EL_QUICKSAND_FAST_EMPTYING))
1493
1494 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1495                                                int graphic)
1496 {
1497   Bitmap *src_bitmap;
1498   int src_x, src_y;
1499   int width, height, cx, cy;
1500   int sx = SCREENX(x), sy = SCREENY(y);
1501   int crumbled_border_size = graphic_info[graphic].border_size;
1502   int i;
1503
1504   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1505
1506   for (i = 1; i < 4; i++)
1507   {
1508     int dxx = (i & 1 ? dx : 0);
1509     int dyy = (i & 2 ? dy : 0);
1510     int xx = x + dxx;
1511     int yy = y + dyy;
1512     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1513                    BorderElement);
1514
1515     /* check if neighbour field is of same crumble type */
1516     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1517                     graphic_info[graphic].class ==
1518                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1519
1520     /* return if check prevents inner corner */
1521     if (same == (dxx == dx && dyy == dy))
1522       return;
1523   }
1524
1525   /* if we reach this point, we have an inner corner */
1526
1527   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1528
1529   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1530   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1531   cx = (dx > 0 ? TILESIZE_VAR - width  : 0);
1532   cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1533
1534   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1535              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1536 }
1537
1538 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1539                                           int dir)
1540 {
1541   Bitmap *src_bitmap;
1542   int src_x, src_y;
1543   int width, height, bx, by, cx, cy;
1544   int sx = SCREENX(x), sy = SCREENY(y);
1545   int crumbled_border_size = graphic_info[graphic].border_size;
1546   int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1547   int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1548   int i;
1549
1550   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1551
1552   /* draw simple, sloppy, non-corner-accurate crumbled border */
1553
1554   width  = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1555   height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1556   cx = (dir == 2 ? crumbled_border_pos_var : 0);
1557   cy = (dir == 3 ? crumbled_border_pos_var : 0);
1558
1559   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1560              FX + sx * TILEX_VAR + cx,
1561              FY + sy * TILEY_VAR + cy);
1562
1563   /* (remaining middle border part must be at least as big as corner part) */
1564   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1565       crumbled_border_size >= TILESIZE / 3)
1566     return;
1567
1568   /* correct corners of crumbled border, if needed */
1569
1570   for (i = -1; i <= 1; i += 2)
1571   {
1572     int xx = x + (dir == 0 || dir == 3 ? i : 0);
1573     int yy = y + (dir == 1 || dir == 2 ? i : 0);
1574     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1575                    BorderElement);
1576
1577     /* check if neighbour field is of same crumble type */
1578     if (IS_CRUMBLED_TILE(xx, yy, element) &&
1579         graphic_info[graphic].class ==
1580         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1581     {
1582       /* no crumbled corner, but continued crumbled border */
1583
1584       int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1585       int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1586       int b1 = (i == 1 ? crumbled_border_size_var :
1587                 TILESIZE_VAR - 2 * crumbled_border_size_var);
1588
1589       width  = crumbled_border_size_var;
1590       height = crumbled_border_size_var;
1591
1592       if (dir == 1 || dir == 2)
1593       {
1594         cx = c1;
1595         cy = c2;
1596         bx = cx;
1597         by = b1;
1598       }
1599       else
1600       {
1601         cx = c2;
1602         cy = c1;
1603         bx = b1;
1604         by = cy;
1605       }
1606
1607       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1608                  width, height,
1609                  FX + sx * TILEX_VAR + cx,
1610                  FY + sy * TILEY_VAR + cy);
1611     }
1612   }
1613 }
1614
1615 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1616 {
1617   int sx = SCREENX(x), sy = SCREENY(y);
1618   int element;
1619   int i;
1620   static int xy[4][2] =
1621   {
1622     { 0, -1 },
1623     { -1, 0 },
1624     { +1, 0 },
1625     { 0, +1 }
1626   };
1627
1628   if (!IN_LEV_FIELD(x, y))
1629     return;
1630
1631   element = TILE_GFX_ELEMENT(x, y);
1632
1633   /* crumble field itself */
1634   if (IS_CRUMBLED_TILE(x, y, element))
1635   {
1636     if (!IN_SCR_FIELD(sx, sy))
1637       return;
1638
1639     for (i = 0; i < 4; i++)
1640     {
1641       int xx = x + xy[i][0];
1642       int yy = y + xy[i][1];
1643
1644       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1645                  BorderElement);
1646
1647       /* check if neighbour field is of same crumble type */
1648       if (IS_CRUMBLED_TILE(xx, yy, element) &&
1649           graphic_info[graphic].class ==
1650           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1651         continue;
1652
1653       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1654     }
1655
1656     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1657         graphic_info[graphic].anim_frames == 2)
1658     {
1659       for (i = 0; i < 4; i++)
1660       {
1661         int dx = (i & 1 ? +1 : -1);
1662         int dy = (i & 2 ? +1 : -1);
1663
1664         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1665       }
1666     }
1667
1668     MarkTileDirty(sx, sy);
1669   }
1670   else          /* center field not crumbled -- crumble neighbour fields */
1671   {
1672     for (i = 0; i < 4; i++)
1673     {
1674       int xx = x + xy[i][0];
1675       int yy = y + xy[i][1];
1676       int sxx = sx + xy[i][0];
1677       int syy = sy + xy[i][1];
1678
1679       if (!IN_LEV_FIELD(xx, yy) ||
1680           !IN_SCR_FIELD(sxx, syy))
1681         continue;
1682
1683       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1684         continue;
1685
1686       element = TILE_GFX_ELEMENT(xx, yy);
1687
1688       if (!IS_CRUMBLED_TILE(xx, yy, element))
1689         continue;
1690
1691       graphic = el_act2crm(element, ACTION_DEFAULT);
1692
1693       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1694
1695       MarkTileDirty(sxx, syy);
1696     }
1697   }
1698 }
1699
1700 void DrawLevelFieldCrumbled(int x, int y)
1701 {
1702   int graphic;
1703
1704   if (!IN_LEV_FIELD(x, y))
1705     return;
1706
1707   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1708       GfxElement[x][y] != EL_UNDEFINED &&
1709       GFX_CRUMBLED(GfxElement[x][y]))
1710   {
1711     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1712
1713     return;
1714   }
1715
1716   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1717
1718   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1719 }
1720
1721 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1722                                    int step_frame)
1723 {
1724   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1725   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1726   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1727   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1728   int sx = SCREENX(x), sy = SCREENY(y);
1729
1730   DrawGraphic(sx, sy, graphic1, frame1);
1731   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1732 }
1733
1734 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1735 {
1736   int sx = SCREENX(x), sy = SCREENY(y);
1737   static int xy[4][2] =
1738   {
1739     { 0, -1 },
1740     { -1, 0 },
1741     { +1, 0 },
1742     { 0, +1 }
1743   };
1744   int i;
1745
1746   for (i = 0; i < 4; i++)
1747   {
1748     int xx = x + xy[i][0];
1749     int yy = y + xy[i][1];
1750     int sxx = sx + xy[i][0];
1751     int syy = sy + xy[i][1];
1752
1753     if (!IN_LEV_FIELD(xx, yy) ||
1754         !IN_SCR_FIELD(sxx, syy) ||
1755         !GFX_CRUMBLED(Feld[xx][yy]) ||
1756         IS_MOVING(xx, yy))
1757       continue;
1758
1759     DrawLevelField(xx, yy);
1760   }
1761 }
1762
1763 static int getBorderElement(int x, int y)
1764 {
1765   int border[7][2] =
1766   {
1767     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
1768     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
1769     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
1770     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1771     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
1772     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
1773     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
1774   };
1775   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1776   int steel_position = (x == -1         && y == -1              ? 0 :
1777                         x == lev_fieldx && y == -1              ? 1 :
1778                         x == -1         && y == lev_fieldy      ? 2 :
1779                         x == lev_fieldx && y == lev_fieldy      ? 3 :
1780                         x == -1         || x == lev_fieldx      ? 4 :
1781                         y == -1         || y == lev_fieldy      ? 5 : 6);
1782
1783   return border[steel_position][steel_type];
1784 }
1785
1786 void DrawScreenElement(int x, int y, int element)
1787 {
1788   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1789   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1790 }
1791
1792 void DrawLevelElement(int x, int y, int element)
1793 {
1794   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1795     DrawScreenElement(SCREENX(x), SCREENY(y), element);
1796 }
1797
1798 void DrawScreenField(int x, int y)
1799 {
1800   int lx = LEVELX(x), ly = LEVELY(y);
1801   int element, content;
1802
1803   if (!IN_LEV_FIELD(lx, ly))
1804   {
1805     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1806       element = EL_EMPTY;
1807     else
1808       element = getBorderElement(lx, ly);
1809
1810     DrawScreenElement(x, y, element);
1811
1812     return;
1813   }
1814
1815   element = Feld[lx][ly];
1816   content = Store[lx][ly];
1817
1818   if (IS_MOVING(lx, ly))
1819   {
1820     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1821     boolean cut_mode = NO_CUTTING;
1822
1823     if (element == EL_QUICKSAND_EMPTYING ||
1824         element == EL_QUICKSAND_FAST_EMPTYING ||
1825         element == EL_MAGIC_WALL_EMPTYING ||
1826         element == EL_BD_MAGIC_WALL_EMPTYING ||
1827         element == EL_DC_MAGIC_WALL_EMPTYING ||
1828         element == EL_AMOEBA_DROPPING)
1829       cut_mode = CUT_ABOVE;
1830     else if (element == EL_QUICKSAND_FILLING ||
1831              element == EL_QUICKSAND_FAST_FILLING ||
1832              element == EL_MAGIC_WALL_FILLING ||
1833              element == EL_BD_MAGIC_WALL_FILLING ||
1834              element == EL_DC_MAGIC_WALL_FILLING)
1835       cut_mode = CUT_BELOW;
1836
1837     if (cut_mode == CUT_ABOVE)
1838       DrawScreenElement(x, y, element);
1839     else
1840       DrawScreenElement(x, y, EL_EMPTY);
1841
1842     if (horiz_move)
1843       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1844     else if (cut_mode == NO_CUTTING)
1845       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1846     else
1847     {
1848       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1849
1850       if (cut_mode == CUT_BELOW &&
1851           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1852         DrawLevelElement(lx, ly + 1, element);
1853     }
1854
1855     if (content == EL_ACID)
1856     {
1857       int dir = MovDir[lx][ly];
1858       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1859       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
1860
1861       DrawLevelElementThruMask(newlx, newly, EL_ACID);
1862     }
1863   }
1864   else if (IS_BLOCKED(lx, ly))
1865   {
1866     int oldx, oldy;
1867     int sx, sy;
1868     int horiz_move;
1869     boolean cut_mode = NO_CUTTING;
1870     int element_old, content_old;
1871
1872     Blocked2Moving(lx, ly, &oldx, &oldy);
1873     sx = SCREENX(oldx);
1874     sy = SCREENY(oldy);
1875     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1876                   MovDir[oldx][oldy] == MV_RIGHT);
1877
1878     element_old = Feld[oldx][oldy];
1879     content_old = Store[oldx][oldy];
1880
1881     if (element_old == EL_QUICKSAND_EMPTYING ||
1882         element_old == EL_QUICKSAND_FAST_EMPTYING ||
1883         element_old == EL_MAGIC_WALL_EMPTYING ||
1884         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1885         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1886         element_old == EL_AMOEBA_DROPPING)
1887       cut_mode = CUT_ABOVE;
1888
1889     DrawScreenElement(x, y, EL_EMPTY);
1890
1891     if (horiz_move)
1892       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1893                                NO_CUTTING);
1894     else if (cut_mode == NO_CUTTING)
1895       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1896                                cut_mode);
1897     else
1898       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1899                                cut_mode);
1900   }
1901   else if (IS_DRAWABLE(element))
1902     DrawScreenElement(x, y, element);
1903   else
1904     DrawScreenElement(x, y, EL_EMPTY);
1905 }
1906
1907 void DrawLevelField(int x, int y)
1908 {
1909   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1910     DrawScreenField(SCREENX(x), SCREENY(y));
1911   else if (IS_MOVING(x, y))
1912   {
1913     int newx,newy;
1914
1915     Moving2Blocked(x, y, &newx, &newy);
1916     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1917       DrawScreenField(SCREENX(newx), SCREENY(newy));
1918   }
1919   else if (IS_BLOCKED(x, y))
1920   {
1921     int oldx, oldy;
1922
1923     Blocked2Moving(x, y, &oldx, &oldy);
1924     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1925       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1926   }
1927 }
1928
1929 void DrawSizedElement(int x, int y, int element, int tilesize)
1930 {
1931   int graphic;
1932
1933   graphic = el2edimg(element);
1934   DrawSizedGraphic(x, y, graphic, 0, tilesize);
1935 }
1936
1937 void DrawMiniElement(int x, int y, int element)
1938 {
1939   int graphic;
1940
1941   graphic = el2edimg(element);
1942   DrawMiniGraphic(x, y, graphic);
1943 }
1944
1945 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1946                             int tilesize)
1947 {
1948   int x = sx + scroll_x, y = sy + scroll_y;
1949
1950   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1951     DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1952   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1953     DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1954   else
1955     DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1956 }
1957
1958 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1959 {
1960   int x = sx + scroll_x, y = sy + scroll_y;
1961
1962   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1963     DrawMiniElement(sx, sy, EL_EMPTY);
1964   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1965     DrawMiniElement(sx, sy, Feld[x][y]);
1966   else
1967     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1968 }
1969
1970 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1971                                  int x, int y, int xsize, int ysize,
1972                                  int tile_width, int tile_height)
1973 {
1974   Bitmap *src_bitmap;
1975   int src_x, src_y;
1976   int dst_x = startx + x * tile_width;
1977   int dst_y = starty + y * tile_height;
1978   int width  = graphic_info[graphic].width;
1979   int height = graphic_info[graphic].height;
1980   int inner_width_raw  = MAX(width  - 2 * tile_width,  tile_width);
1981   int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1982   int inner_width  = inner_width_raw  - (inner_width_raw  % tile_width);
1983   int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1984   int inner_sx = (width  >= 3 * tile_width  ? tile_width  : 0);
1985   int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1986   boolean draw_masked = graphic_info[graphic].draw_masked;
1987
1988   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1989
1990   if (src_bitmap == NULL || width < tile_width || height < tile_height)
1991   {
1992     ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1993     return;
1994   }
1995
1996   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - tile_width  :
1997             inner_sx + (x - 1) * tile_width  % inner_width);
1998   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1999             inner_sy + (y - 1) * tile_height % inner_height);
2000
2001   if (draw_masked)
2002     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2003                      dst_x, dst_y);
2004   else
2005     BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2006                dst_x, dst_y);
2007 }
2008
2009 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2010                             int x, int y, int xsize, int ysize, int font_nr)
2011 {
2012   int font_width  = getFontWidth(font_nr);
2013   int font_height = getFontHeight(font_nr);
2014
2015   DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2016                               font_width, font_height);
2017 }
2018
2019 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2020 {
2021   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2022   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2023   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2024   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2025   boolean no_delay = (tape.warp_forward);
2026   unsigned int anim_delay = 0;
2027   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2028   int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2029   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2030   int font_width = getFontWidth(font_nr);
2031   int font_height = getFontHeight(font_nr);
2032   int max_xsize = level.envelope[envelope_nr].xsize;
2033   int max_ysize = level.envelope[envelope_nr].ysize;
2034   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2035   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2036   int xend = max_xsize;
2037   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2038   int xstep = (xstart < xend ? 1 : 0);
2039   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2040   int start = 0;
2041   int end = MAX(xend - xstart, yend - ystart);
2042   int i;
2043
2044   for (i = start; i <= end; i++)
2045   {
2046     int last_frame = end;       // last frame of this "for" loop
2047     int x = xstart + i * xstep;
2048     int y = ystart + i * ystep;
2049     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2050     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2051     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
2052     int sy = SY + (SYSIZE - ysize * font_height) / 2;
2053     int xx, yy;
2054
2055     SetDrawtoField(DRAW_FIELDBUFFER);
2056
2057     BlitScreenToBitmap(backbuffer);
2058
2059     SetDrawtoField(DRAW_BACKBUFFER);
2060
2061     for (yy = 0; yy < ysize; yy++)
2062       for (xx = 0; xx < xsize; xx++)
2063         DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2064
2065     DrawTextBuffer(sx + font_width, sy + font_height,
2066                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2067                    xsize - 2, ysize - 2, 0, mask_mode,
2068                    level.envelope[envelope_nr].autowrap,
2069                    level.envelope[envelope_nr].centered, FALSE);
2070
2071     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2072     BackToFront();
2073
2074     SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2075   }
2076 }
2077
2078 void ShowEnvelope(int envelope_nr)
2079 {
2080   int element = EL_ENVELOPE_1 + envelope_nr;
2081   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2082   int sound_opening = element_info[element].sound[ACTION_OPENING];
2083   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2084   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2085   boolean no_delay = (tape.warp_forward);
2086   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2087   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2088   int anim_mode = graphic_info[graphic].anim_mode;
2089   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2090                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2091
2092   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2093
2094   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2095
2096   if (anim_mode == ANIM_DEFAULT)
2097     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2098
2099   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2100
2101   if (tape.playing)
2102     Delay(wait_delay_value);
2103   else
2104     WaitForEventToContinue();
2105
2106   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2107
2108   if (anim_mode != ANIM_NONE)
2109     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2110
2111   if (anim_mode == ANIM_DEFAULT)
2112     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2113
2114   game.envelope_active = FALSE;
2115
2116   SetDrawtoField(DRAW_FIELDBUFFER);
2117
2118   redraw_mask |= REDRAW_FIELD;
2119   BackToFront();
2120 }
2121
2122 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2123 {
2124   int border_size = request.border_size;
2125   int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2126   int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2127   int sx = sx_center - request.width  / 2;
2128   int sy = sy_center - request.height / 2;
2129
2130   if (add_border_size)
2131   {
2132     sx += border_size;
2133     sy += border_size;
2134   }
2135
2136   *x = sx;
2137   *y = sy;
2138 }
2139
2140 void DrawEnvelopeRequest(char *text)
2141 {
2142   char *text_final = text;
2143   char *text_door_style = NULL;
2144   int graphic = IMG_BACKGROUND_REQUEST;
2145   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2146   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2147   int font_nr = FONT_REQUEST;
2148   int font_width = getFontWidth(font_nr);
2149   int font_height = getFontHeight(font_nr);
2150   int border_size = request.border_size;
2151   int line_spacing = request.line_spacing;
2152   int line_height = font_height + line_spacing;
2153   int text_width = request.width - 2 * border_size;
2154   int text_height = request.height - 2 * border_size;
2155   int line_length = text_width / font_width;
2156   int max_lines = text_height / line_height;
2157   int width = request.width;
2158   int height = request.height;
2159   int tile_size = request.step_offset;
2160   int x_steps = width  / tile_size;
2161   int y_steps = height / tile_size;
2162   int sx, sy;
2163   int i, x, y;
2164
2165   if (request.wrap_single_words)
2166   {
2167     char *src_text_ptr, *dst_text_ptr;
2168
2169     text_door_style = checked_malloc(2 * strlen(text) + 1);
2170
2171     src_text_ptr = text;
2172     dst_text_ptr = text_door_style;
2173
2174     while (*src_text_ptr)
2175     {
2176       if (*src_text_ptr == ' ' ||
2177           *src_text_ptr == '?' ||
2178           *src_text_ptr == '!')
2179         *dst_text_ptr++ = '\n';
2180
2181       if (*src_text_ptr != ' ')
2182         *dst_text_ptr++ = *src_text_ptr;
2183
2184       src_text_ptr++;
2185     }
2186
2187     *dst_text_ptr = '\0';
2188
2189     text_final = text_door_style;
2190   }
2191
2192   setRequestPosition(&sx, &sy, FALSE);
2193
2194   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2195
2196   for (y = 0; y < y_steps; y++)
2197     for (x = 0; x < x_steps; x++)
2198       DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2199                                   x, y, x_steps, y_steps,
2200                                   tile_size, tile_size);
2201
2202   DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2203                  line_length, -1, max_lines, line_spacing, mask_mode,
2204                  request.autowrap, request.centered, FALSE);
2205
2206   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2207     RedrawGadget(tool_gadget[i]);
2208
2209   // store readily prepared envelope request for later use when animating
2210   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2211
2212   if (text_door_style)
2213     free(text_door_style);
2214 }
2215
2216 void AnimateEnvelopeRequest(int anim_mode, int action)
2217 {
2218   int graphic = IMG_BACKGROUND_REQUEST;
2219   boolean draw_masked = graphic_info[graphic].draw_masked;
2220   int delay_value_normal = request.step_delay;
2221   int delay_value_fast = delay_value_normal / 2;
2222   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2223   boolean no_delay = (tape.warp_forward);
2224   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2225   int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2226   unsigned int anim_delay = 0;
2227
2228   int width = request.width;
2229   int height = request.height;
2230   int tile_size = request.step_offset;
2231   int max_xsize = width  / tile_size;
2232   int max_ysize = height / tile_size;
2233   int max_xsize_inner = max_xsize - 2;
2234   int max_ysize_inner = max_ysize - 2;
2235
2236   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2237   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2238   int xend = max_xsize_inner;
2239   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2240   int xstep = (xstart < xend ? 1 : 0);
2241   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2242   int start = 0;
2243   int end = MAX(xend - xstart, yend - ystart);
2244   int i;
2245
2246   if (setup.quick_doors)
2247   {
2248     xstart = xend;
2249     ystart = yend;
2250     end = 0;
2251   }
2252   else
2253   {
2254     if (action == ACTION_OPENING)
2255       PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2256     else if (action == ACTION_CLOSING)
2257       PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2258   }
2259
2260   for (i = start; i <= end; i++)
2261   {
2262     int last_frame = end;       // last frame of this "for" loop
2263     int x = xstart + i * xstep;
2264     int y = ystart + i * ystep;
2265     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2266     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2267     int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2268     int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2269     int src_x = sx_center - width  / 2;
2270     int src_y = sy_center - height / 2;
2271     int dst_x = sx_center - xsize * tile_size / 2;
2272     int dst_y = sy_center - ysize * tile_size / 2;
2273     int xsize_size_left = (xsize - 1) * tile_size;
2274     int ysize_size_top  = (ysize - 1) * tile_size;
2275     int max_xsize_pos = (max_xsize - 1) * tile_size;
2276     int max_ysize_pos = (max_ysize - 1) * tile_size;
2277     int xx, yy;
2278
2279     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2280
2281     for (yy = 0; yy < 2; yy++)
2282     {
2283       for (xx = 0; xx < 2; xx++)
2284       {
2285         int src_xx = src_x + xx * max_xsize_pos;
2286         int src_yy = src_y + yy * max_ysize_pos;
2287         int dst_xx = dst_x + xx * xsize_size_left;
2288         int dst_yy = dst_y + yy * ysize_size_top;
2289         int xx_size = (xx ? tile_size : xsize_size_left);
2290         int yy_size = (yy ? tile_size : ysize_size_top);
2291
2292         if (draw_masked)
2293           BlitBitmapMasked(bitmap_db_cross, backbuffer,
2294                            src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2295         else
2296           BlitBitmap(bitmap_db_cross, backbuffer,
2297                      src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2298       }
2299     }
2300
2301     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2302
2303     DoAnimation();
2304     BackToFront();
2305
2306     SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2307   }
2308 }
2309
2310
2311 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2312 {
2313   int last_game_status = game_status;   /* save current game status */
2314   int graphic = IMG_BACKGROUND_REQUEST;
2315   int sound_opening = SND_REQUEST_OPENING;
2316   int sound_closing = SND_REQUEST_CLOSING;
2317   int anim_mode = graphic_info[graphic].anim_mode;
2318   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2319                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2320
2321   if (game_status == GAME_MODE_PLAYING)
2322     BlitScreenToBitmap(backbuffer);
2323
2324   SetDrawtoField(DRAW_BACKBUFFER);
2325
2326   // SetDrawBackgroundMask(REDRAW_NONE);
2327
2328   if (action == ACTION_OPENING)
2329   {
2330     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2331
2332     if (req_state & REQ_ASK)
2333     {
2334       MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2335       MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2336     }
2337     else if (req_state & REQ_CONFIRM)
2338     {
2339       MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2340     }
2341     else if (req_state & REQ_PLAYER)
2342     {
2343       MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2344       MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2345       MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2346       MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2347     }
2348
2349     DrawEnvelopeRequest(text);
2350
2351     if (game_status != GAME_MODE_MAIN)
2352       InitAnimation();
2353   }
2354
2355   /* force DOOR font inside door area */
2356   game_status = GAME_MODE_PSEUDO_DOOR;
2357
2358   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2359
2360   if (action == ACTION_OPENING)
2361   {
2362     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2363
2364     if (anim_mode == ANIM_DEFAULT)
2365       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2366
2367     AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2368   }
2369   else
2370   {
2371     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2372
2373     if (anim_mode != ANIM_NONE)
2374       AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2375
2376     if (anim_mode == ANIM_DEFAULT)
2377       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2378   }
2379
2380   game.envelope_active = FALSE;
2381
2382   game_status = last_game_status;       /* restore current game status */
2383
2384   if (action == ACTION_CLOSING)
2385   {
2386     if (game_status != GAME_MODE_MAIN)
2387       StopAnimation();
2388
2389     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2390   }
2391
2392   // SetDrawBackgroundMask(last_draw_background_mask);
2393
2394   redraw_mask |= REDRAW_FIELD;
2395
2396   if (game_status == GAME_MODE_MAIN)
2397     DoAnimation();
2398
2399   BackToFront();
2400
2401   if (action == ACTION_CLOSING &&
2402       game_status == GAME_MODE_PLAYING &&
2403       level.game_engine_type == GAME_ENGINE_TYPE_RND)
2404     SetDrawtoField(DRAW_FIELDBUFFER);
2405 }
2406
2407 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2408 {
2409   Bitmap *src_bitmap;
2410   int src_x, src_y;
2411   int graphic = el2preimg(element);
2412
2413   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2414   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2415 }
2416
2417 void DrawLevel(int draw_background_mask)
2418 {
2419   int x,y;
2420
2421   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2422   SetDrawBackgroundMask(draw_background_mask);
2423
2424   ClearField();
2425
2426   for (x = BX1; x <= BX2; x++)
2427     for (y = BY1; y <= BY2; y++)
2428       DrawScreenField(x, y);
2429
2430   redraw_mask |= REDRAW_FIELD;
2431 }
2432
2433 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2434                     int tilesize)
2435 {
2436   int x,y;
2437
2438   for (x = 0; x < size_x; x++)
2439     for (y = 0; y < size_y; y++)
2440       DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2441
2442   redraw_mask |= REDRAW_FIELD;
2443 }
2444
2445 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2446 {
2447   int x,y;
2448
2449   for (x = 0; x < size_x; x++)
2450     for (y = 0; y < size_y; y++)
2451       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2452
2453   redraw_mask |= REDRAW_FIELD;
2454 }
2455
2456 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2457 {
2458   boolean show_level_border = (BorderElement != EL_EMPTY);
2459   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2460   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2461   int tile_size = preview.tile_size;
2462   int preview_width  = preview.xsize * tile_size;
2463   int preview_height = preview.ysize * tile_size;
2464   int real_preview_xsize = MIN(level_xsize, preview.xsize);
2465   int real_preview_ysize = MIN(level_ysize, preview.ysize);
2466   int real_preview_width  = real_preview_xsize * tile_size;
2467   int real_preview_height = real_preview_ysize * tile_size;
2468   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2469   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2470   int x, y;
2471
2472   if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2473     return;
2474
2475   DrawBackground(dst_x, dst_y, preview_width, preview_height);
2476
2477   dst_x += (preview_width  - real_preview_width)  / 2;
2478   dst_y += (preview_height - real_preview_height) / 2;
2479
2480   for (x = 0; x < real_preview_xsize; x++)
2481   {
2482     for (y = 0; y < real_preview_ysize; y++)
2483     {
2484       int lx = from_x + x + (show_level_border ? -1 : 0);
2485       int ly = from_y + y + (show_level_border ? -1 : 0);
2486       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2487                      getBorderElement(lx, ly));
2488
2489       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2490                          element, tile_size);
2491     }
2492   }
2493
2494   redraw_mask |= REDRAW_MICROLEVEL;
2495 }
2496
2497 #define MICROLABEL_EMPTY                0
2498 #define MICROLABEL_LEVEL_NAME           1
2499 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
2500 #define MICROLABEL_LEVEL_AUTHOR         3
2501 #define MICROLABEL_IMPORTED_FROM_HEAD   4
2502 #define MICROLABEL_IMPORTED_FROM        5
2503 #define MICROLABEL_IMPORTED_BY_HEAD     6
2504 #define MICROLABEL_IMPORTED_BY          7
2505
2506 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2507 {
2508   int max_text_width = SXSIZE;
2509   int font_width = getFontWidth(font_nr);
2510
2511   if (pos->align == ALIGN_CENTER)
2512     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2513   else if (pos->align == ALIGN_RIGHT)
2514     max_text_width = pos->x;
2515   else
2516     max_text_width = SXSIZE - pos->x;
2517
2518   return max_text_width / font_width;
2519 }
2520
2521 static void DrawPreviewLevelLabelExt(int mode)
2522 {
2523   struct TextPosInfo *pos = &menu.main.text.level_info_2;
2524   char label_text[MAX_OUTPUT_LINESIZE + 1];
2525   int max_len_label_text;
2526   int font_nr = pos->font;
2527   int i;
2528
2529   if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2530     return;
2531
2532   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2533       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2534       mode == MICROLABEL_IMPORTED_BY_HEAD)
2535     font_nr = pos->font_alt;
2536
2537   max_len_label_text = getMaxTextLength(pos, font_nr);
2538
2539   if (pos->size != -1)
2540     max_len_label_text = pos->size;
2541
2542   for (i = 0; i < max_len_label_text; i++)
2543     label_text[i] = ' ';
2544   label_text[max_len_label_text] = '\0';
2545
2546   if (strlen(label_text) > 0)
2547     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2548
2549   strncpy(label_text,
2550           (mode == MICROLABEL_LEVEL_NAME ? level.name :
2551            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2552            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2553            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2554            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2555            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2556            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2557           max_len_label_text);
2558   label_text[max_len_label_text] = '\0';
2559
2560   if (strlen(label_text) > 0)
2561     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2562
2563   redraw_mask |= REDRAW_MICROLEVEL;
2564 }
2565
2566 static void DrawPreviewLevelExt(boolean restart)
2567 {
2568   static unsigned int scroll_delay = 0;
2569   static unsigned int label_delay = 0;
2570   static int from_x, from_y, scroll_direction;
2571   static int label_state, label_counter;
2572   unsigned int scroll_delay_value = preview.step_delay;
2573   boolean show_level_border = (BorderElement != EL_EMPTY);
2574   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2575   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2576   int last_game_status = game_status;           /* save current game status */
2577
2578   if (restart)
2579   {
2580     from_x = 0;
2581     from_y = 0;
2582
2583     if (preview.anim_mode == ANIM_CENTERED)
2584     {
2585       if (level_xsize > preview.xsize)
2586         from_x = (level_xsize - preview.xsize) / 2;
2587       if (level_ysize > preview.ysize)
2588         from_y = (level_ysize - preview.ysize) / 2;
2589     }
2590
2591     from_x += preview.xoffset;
2592     from_y += preview.yoffset;
2593
2594     scroll_direction = MV_RIGHT;
2595     label_state = 1;
2596     label_counter = 0;
2597
2598     DrawPreviewLevelPlayfieldExt(from_x, from_y);
2599     DrawPreviewLevelLabelExt(label_state);
2600
2601     /* initialize delay counters */
2602     DelayReached(&scroll_delay, 0);
2603     DelayReached(&label_delay, 0);
2604
2605     if (leveldir_current->name)
2606     {
2607       struct TextPosInfo *pos = &menu.main.text.level_info_1;
2608       char label_text[MAX_OUTPUT_LINESIZE + 1];
2609       int font_nr = pos->font;
2610       int max_len_label_text = getMaxTextLength(pos, font_nr);
2611
2612       if (pos->size != -1)
2613         max_len_label_text = pos->size;
2614
2615       strncpy(label_text, leveldir_current->name, max_len_label_text);
2616       label_text[max_len_label_text] = '\0';
2617
2618       if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2619         DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2620     }
2621
2622     game_status = last_game_status;     /* restore current game status */
2623
2624     return;
2625   }
2626
2627   /* scroll preview level, if needed */
2628   if (preview.anim_mode != ANIM_NONE &&
2629       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2630       DelayReached(&scroll_delay, scroll_delay_value))
2631   {
2632     switch (scroll_direction)
2633     {
2634       case MV_LEFT:
2635         if (from_x > 0)
2636         {
2637           from_x -= preview.step_offset;
2638           from_x = (from_x < 0 ? 0 : from_x);
2639         }
2640         else
2641           scroll_direction = MV_UP;
2642         break;
2643
2644       case MV_RIGHT:
2645         if (from_x < level_xsize - preview.xsize)
2646         {
2647           from_x += preview.step_offset;
2648           from_x = (from_x > level_xsize - preview.xsize ?
2649                     level_xsize - preview.xsize : from_x);
2650         }
2651         else
2652           scroll_direction = MV_DOWN;
2653         break;
2654
2655       case MV_UP:
2656         if (from_y > 0)
2657         {
2658           from_y -= preview.step_offset;
2659           from_y = (from_y < 0 ? 0 : from_y);
2660         }
2661         else
2662           scroll_direction = MV_RIGHT;
2663         break;
2664
2665       case MV_DOWN:
2666         if (from_y < level_ysize - preview.ysize)
2667         {
2668           from_y += preview.step_offset;
2669           from_y = (from_y > level_ysize - preview.ysize ?
2670                     level_ysize - preview.ysize : from_y);
2671         }
2672         else
2673           scroll_direction = MV_LEFT;
2674         break;
2675
2676       default:
2677         break;
2678     }
2679
2680     DrawPreviewLevelPlayfieldExt(from_x, from_y);
2681   }
2682
2683   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2684   /* redraw micro level label, if needed */
2685   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2686       !strEqual(level.author, ANONYMOUS_NAME) &&
2687       !strEqual(level.author, leveldir_current->name) &&
2688       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2689   {
2690     int max_label_counter = 23;
2691
2692     if (leveldir_current->imported_from != NULL &&
2693         strlen(leveldir_current->imported_from) > 0)
2694       max_label_counter += 14;
2695     if (leveldir_current->imported_by != NULL &&
2696         strlen(leveldir_current->imported_by) > 0)
2697       max_label_counter += 14;
2698
2699     label_counter = (label_counter + 1) % max_label_counter;
2700     label_state = (label_counter >= 0 && label_counter <= 7 ?
2701                    MICROLABEL_LEVEL_NAME :
2702                    label_counter >= 9 && label_counter <= 12 ?
2703                    MICROLABEL_LEVEL_AUTHOR_HEAD :
2704                    label_counter >= 14 && label_counter <= 21 ?
2705                    MICROLABEL_LEVEL_AUTHOR :
2706                    label_counter >= 23 && label_counter <= 26 ?
2707                    MICROLABEL_IMPORTED_FROM_HEAD :
2708                    label_counter >= 28 && label_counter <= 35 ?
2709                    MICROLABEL_IMPORTED_FROM :
2710                    label_counter >= 37 && label_counter <= 40 ?
2711                    MICROLABEL_IMPORTED_BY_HEAD :
2712                    label_counter >= 42 && label_counter <= 49 ?
2713                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2714
2715     if (leveldir_current->imported_from == NULL &&
2716         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2717          label_state == MICROLABEL_IMPORTED_FROM))
2718       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2719                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2720
2721     DrawPreviewLevelLabelExt(label_state);
2722   }
2723
2724   game_status = last_game_status;       /* restore current game status */
2725 }
2726
2727 void DrawPreviewLevelInitial()
2728 {
2729   DrawPreviewLevelExt(TRUE);
2730 }
2731
2732 void DrawPreviewLevelAnimation()
2733 {
2734   DrawPreviewLevelExt(FALSE);
2735 }
2736
2737 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2738                                     int graphic, int sync_frame, int mask_mode)
2739 {
2740   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2741
2742   if (mask_mode == USE_MASKING)
2743     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2744   else
2745     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2746 }
2747
2748 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2749                                          int graphic, int sync_frame,
2750                                          int mask_mode)
2751 {
2752   int frame = getGraphicAnimationFrame(graphic, sync_frame);
2753
2754   if (mask_mode == USE_MASKING)
2755     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2756   else
2757     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2758 }
2759
2760 inline void DrawGraphicAnimation(int x, int y, int graphic)
2761 {
2762   int lx = LEVELX(x), ly = LEVELY(y);
2763
2764   if (!IN_SCR_FIELD(x, y))
2765     return;
2766
2767   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2768                           graphic, GfxFrame[lx][ly], NO_MASKING);
2769
2770   MarkTileDirty(x, y);
2771 }
2772
2773 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2774 {
2775   int lx = LEVELX(x), ly = LEVELY(y);
2776
2777   if (!IN_SCR_FIELD(x, y))
2778     return;
2779
2780   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2781                           graphic, GfxFrame[lx][ly], NO_MASKING);
2782   MarkTileDirty(x, y);
2783 }
2784
2785 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2786 {
2787   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2788 }
2789
2790 void DrawLevelElementAnimation(int x, int y, int element)
2791 {
2792   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2793
2794   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2795 }
2796
2797 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2798 {
2799   int sx = SCREENX(x), sy = SCREENY(y);
2800
2801   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2802     return;
2803
2804   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2805     return;
2806
2807   DrawGraphicAnimation(sx, sy, graphic);
2808
2809 #if 1
2810   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2811     DrawLevelFieldCrumbled(x, y);
2812 #else
2813   if (GFX_CRUMBLED(Feld[x][y]))
2814     DrawLevelFieldCrumbled(x, y);
2815 #endif
2816 }
2817
2818 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2819 {
2820   int sx = SCREENX(x), sy = SCREENY(y);
2821   int graphic;
2822
2823   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2824     return;
2825
2826   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2827
2828   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2829     return;
2830
2831   DrawGraphicAnimation(sx, sy, graphic);
2832
2833   if (GFX_CRUMBLED(element))
2834     DrawLevelFieldCrumbled(x, y);
2835 }
2836
2837 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2838 {
2839   if (player->use_murphy)
2840   {
2841     /* this works only because currently only one player can be "murphy" ... */
2842     static int last_horizontal_dir = MV_LEFT;
2843     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2844
2845     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2846       last_horizontal_dir = move_dir;
2847
2848     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
2849     {
2850       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2851
2852       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2853     }
2854
2855     return graphic;
2856   }
2857   else
2858     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2859 }
2860
2861 static boolean equalGraphics(int graphic1, int graphic2)
2862 {
2863   struct GraphicInfo *g1 = &graphic_info[graphic1];
2864   struct GraphicInfo *g2 = &graphic_info[graphic2];
2865
2866   return (g1->bitmap      == g2->bitmap &&
2867           g1->src_x       == g2->src_x &&
2868           g1->src_y       == g2->src_y &&
2869           g1->anim_frames == g2->anim_frames &&
2870           g1->anim_delay  == g2->anim_delay &&
2871           g1->anim_mode   == g2->anim_mode);
2872 }
2873
2874 void DrawAllPlayers()
2875 {
2876   int i;
2877
2878   for (i = 0; i < MAX_PLAYERS; i++)
2879     if (stored_player[i].active)
2880       DrawPlayer(&stored_player[i]);
2881 }
2882
2883 void DrawPlayerField(int x, int y)
2884 {
2885   if (!IS_PLAYER(x, y))
2886     return;
2887
2888   DrawPlayer(PLAYERINFO(x, y));
2889 }
2890
2891 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2892
2893 void DrawPlayer(struct PlayerInfo *player)
2894 {
2895   int jx = player->jx;
2896   int jy = player->jy;
2897   int move_dir = player->MovDir;
2898   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2899   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
2900   int last_jx = (player->is_moving ? jx - dx : jx);
2901   int last_jy = (player->is_moving ? jy - dy : jy);
2902   int next_jx = jx + dx;
2903   int next_jy = jy + dy;
2904   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2905   boolean player_is_opaque = FALSE;
2906   int sx = SCREENX(jx), sy = SCREENY(jy);
2907   int sxx = 0, syy = 0;
2908   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2909   int graphic;
2910   int action = ACTION_DEFAULT;
2911   int last_player_graphic = getPlayerGraphic(player, move_dir);
2912   int last_player_frame = player->Frame;
2913   int frame = 0;
2914
2915   /* GfxElement[][] is set to the element the player is digging or collecting;
2916      remove also for off-screen player if the player is not moving anymore */
2917   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2918     GfxElement[jx][jy] = EL_UNDEFINED;
2919
2920   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2921     return;
2922
2923 #if DEBUG
2924   if (!IN_LEV_FIELD(jx, jy))
2925   {
2926     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2927     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2928     printf("DrawPlayerField(): This should never happen!\n");
2929     return;
2930   }
2931 #endif
2932
2933   if (element == EL_EXPLOSION)
2934     return;
2935
2936   action = (player->is_pushing    ? ACTION_PUSHING         :
2937             player->is_digging    ? ACTION_DIGGING         :
2938             player->is_collecting ? ACTION_COLLECTING      :
2939             player->is_moving     ? ACTION_MOVING          :
2940             player->is_snapping   ? ACTION_SNAPPING        :
2941             player->is_dropping   ? ACTION_DROPPING        :
2942             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
2943
2944   if (player->is_waiting)
2945     move_dir = player->dir_waiting;
2946
2947   InitPlayerGfxAnimation(player, action, move_dir);
2948
2949   /* ----------------------------------------------------------------------- */
2950   /* draw things in the field the player is leaving, if needed               */
2951   /* ----------------------------------------------------------------------- */
2952
2953   if (player->is_moving)
2954   {
2955     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2956     {
2957       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2958
2959       if (last_element == EL_DYNAMITE_ACTIVE ||
2960           last_element == EL_EM_DYNAMITE_ACTIVE ||
2961           last_element == EL_SP_DISK_RED_ACTIVE)
2962         DrawDynamite(last_jx, last_jy);
2963       else
2964         DrawLevelFieldThruMask(last_jx, last_jy);
2965     }
2966     else if (last_element == EL_DYNAMITE_ACTIVE ||
2967              last_element == EL_EM_DYNAMITE_ACTIVE ||
2968              last_element == EL_SP_DISK_RED_ACTIVE)
2969       DrawDynamite(last_jx, last_jy);
2970 #if 0
2971     /* !!! this is not enough to prevent flickering of players which are
2972        moving next to each others without a free tile between them -- this
2973        can only be solved by drawing all players layer by layer (first the
2974        background, then the foreground etc.) !!! => TODO */
2975     else if (!IS_PLAYER(last_jx, last_jy))
2976       DrawLevelField(last_jx, last_jy);
2977 #else
2978     else
2979       DrawLevelField(last_jx, last_jy);
2980 #endif
2981
2982     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2983       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2984   }
2985
2986   if (!IN_SCR_FIELD(sx, sy))
2987     return;
2988
2989   /* ----------------------------------------------------------------------- */
2990   /* draw things behind the player, if needed                                */
2991   /* ----------------------------------------------------------------------- */
2992
2993   if (Back[jx][jy])
2994     DrawLevelElement(jx, jy, Back[jx][jy]);
2995   else if (IS_ACTIVE_BOMB(element))
2996     DrawLevelElement(jx, jy, EL_EMPTY);
2997   else
2998   {
2999     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3000     {
3001       int old_element = GfxElement[jx][jy];
3002       int old_graphic = el_act_dir2img(old_element, action, move_dir);
3003       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3004
3005       if (GFX_CRUMBLED(old_element))
3006         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3007       else
3008         DrawGraphic(sx, sy, old_graphic, frame);
3009
3010       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3011         player_is_opaque = TRUE;
3012     }
3013     else
3014     {
3015       GfxElement[jx][jy] = EL_UNDEFINED;
3016
3017       /* make sure that pushed elements are drawn with correct frame rate */
3018       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3019
3020       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3021         GfxFrame[jx][jy] = player->StepFrame;
3022
3023       DrawLevelField(jx, jy);
3024     }
3025   }
3026
3027 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3028   /* ----------------------------------------------------------------------- */
3029   /* draw player himself                                                     */
3030   /* ----------------------------------------------------------------------- */
3031
3032   graphic = getPlayerGraphic(player, move_dir);
3033
3034   /* in the case of changed player action or direction, prevent the current
3035      animation frame from being restarted for identical animations */
3036   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3037     player->Frame = last_player_frame;
3038
3039   frame = getGraphicAnimationFrame(graphic, player->Frame);
3040
3041   if (player->GfxPos)
3042   {
3043     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3044       sxx = player->GfxPos;
3045     else
3046       syy = player->GfxPos;
3047   }
3048
3049   if (player_is_opaque)
3050     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3051   else
3052     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3053
3054   if (SHIELD_ON(player))
3055   {
3056     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3057                    IMG_SHIELD_NORMAL_ACTIVE);
3058     int frame = getGraphicAnimationFrame(graphic, -1);
3059
3060     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3061   }
3062 #endif
3063
3064 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3065   if (player->GfxPos)
3066   {
3067     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3068       sxx = player->GfxPos;
3069     else
3070       syy = player->GfxPos;
3071   }
3072 #endif
3073
3074   /* ----------------------------------------------------------------------- */
3075   /* draw things the player is pushing, if needed                            */
3076   /* ----------------------------------------------------------------------- */
3077
3078   if (player->is_pushing && player->is_moving)
3079   {
3080     int px = SCREENX(jx), py = SCREENY(jy);
3081     int pxx = (TILEX - ABS(sxx)) * dx;
3082     int pyy = (TILEY - ABS(syy)) * dy;
3083     int gfx_frame = GfxFrame[jx][jy];
3084
3085     int graphic;
3086     int sync_frame;
3087     int frame;
3088
3089     if (!IS_MOVING(jx, jy))             /* push movement already finished */
3090     {
3091       element = Feld[next_jx][next_jy];
3092       gfx_frame = GfxFrame[next_jx][next_jy];
3093     }
3094
3095     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3096
3097     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3098     frame = getGraphicAnimationFrame(graphic, sync_frame);
3099
3100     /* draw background element under pushed element (like the Sokoban field) */
3101     if (game.use_masked_pushing && IS_MOVING(jx, jy))
3102     {
3103       /* this allows transparent pushing animation over non-black background */
3104
3105       if (Back[jx][jy])
3106         DrawLevelElement(jx, jy, Back[jx][jy]);
3107       else
3108         DrawLevelElement(jx, jy, EL_EMPTY);
3109
3110       if (Back[next_jx][next_jy])
3111         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3112       else
3113         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3114     }
3115     else if (Back[next_jx][next_jy])
3116       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3117
3118 #if 1
3119     /* do not draw (EM style) pushing animation when pushing is finished */
3120     /* (two-tile animations usually do not contain start and end frame) */
3121     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3122       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3123     else
3124       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3125 #else
3126     /* masked drawing is needed for EMC style (double) movement graphics */
3127     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3128     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3129 #endif
3130   }
3131
3132 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3133   /* ----------------------------------------------------------------------- */
3134   /* draw player himself                                                     */
3135   /* ----------------------------------------------------------------------- */
3136
3137   graphic = getPlayerGraphic(player, move_dir);
3138
3139   /* in the case of changed player action or direction, prevent the current
3140      animation frame from being restarted for identical animations */
3141   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3142     player->Frame = last_player_frame;
3143
3144   frame = getGraphicAnimationFrame(graphic, player->Frame);
3145
3146   if (player->GfxPos)
3147   {
3148     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3149       sxx = player->GfxPos;
3150     else
3151       syy = player->GfxPos;
3152   }
3153
3154   if (player_is_opaque)
3155     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3156   else
3157     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3158
3159   if (SHIELD_ON(player))
3160   {
3161     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3162                    IMG_SHIELD_NORMAL_ACTIVE);
3163     int frame = getGraphicAnimationFrame(graphic, -1);
3164
3165     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3166   }
3167 #endif
3168
3169   /* ----------------------------------------------------------------------- */
3170   /* draw things in front of player (active dynamite or dynabombs)           */
3171   /* ----------------------------------------------------------------------- */
3172
3173   if (IS_ACTIVE_BOMB(element))
3174   {
3175     graphic = el2img(element);
3176     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3177
3178     if (game.emulation == EMU_SUPAPLEX)
3179       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3180     else
3181       DrawGraphicThruMask(sx, sy, graphic, frame);
3182   }
3183
3184   if (player_is_moving && last_element == EL_EXPLOSION)
3185   {
3186     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3187                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
3188     int graphic = el_act2img(element, ACTION_EXPLODING);
3189     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3190     int phase = ExplodePhase[last_jx][last_jy] - 1;
3191     int frame = getGraphicAnimationFrame(graphic, phase - delay);
3192
3193     if (phase >= delay)
3194       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3195   }
3196
3197   /* ----------------------------------------------------------------------- */
3198   /* draw elements the player is just walking/passing through/under          */
3199   /* ----------------------------------------------------------------------- */
3200
3201   if (player_is_moving)
3202   {
3203     /* handle the field the player is leaving ... */
3204     if (IS_ACCESSIBLE_INSIDE(last_element))
3205       DrawLevelField(last_jx, last_jy);
3206     else if (IS_ACCESSIBLE_UNDER(last_element))
3207       DrawLevelFieldThruMask(last_jx, last_jy);
3208   }
3209
3210   /* do not redraw accessible elements if the player is just pushing them */
3211   if (!player_is_moving || !player->is_pushing)
3212   {
3213     /* ... and the field the player is entering */
3214     if (IS_ACCESSIBLE_INSIDE(element))
3215       DrawLevelField(jx, jy);
3216     else if (IS_ACCESSIBLE_UNDER(element))
3217       DrawLevelFieldThruMask(jx, jy);
3218   }
3219
3220   MarkTileDirty(sx, sy);
3221 }
3222
3223 /* ------------------------------------------------------------------------- */
3224
3225 void WaitForEventToContinue()
3226 {
3227   boolean still_wait = TRUE;
3228
3229   /* simulate releasing mouse button over last gadget, if still pressed */
3230   if (button_status)
3231     HandleGadgets(-1, -1, 0);
3232
3233   button_status = MB_RELEASED;
3234
3235   ClearEventQueue();
3236
3237   while (still_wait)
3238   {
3239     if (PendingEvent())
3240     {
3241       Event event;
3242
3243       NextEvent(&event);
3244
3245       switch (event.type)
3246       {
3247         case EVENT_BUTTONPRESS:
3248         case EVENT_KEYPRESS:
3249           still_wait = FALSE;
3250           break;
3251
3252         case EVENT_KEYRELEASE:
3253           ClearPlayerAction();
3254           break;
3255
3256         default:
3257           HandleOtherEvents(&event);
3258           break;
3259       }
3260     }
3261     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3262     {
3263       still_wait = FALSE;
3264     }
3265
3266     DoAnimation();
3267
3268     /* don't eat all CPU time */
3269     Delay(10);
3270   }
3271 }
3272
3273 #define MAX_REQUEST_LINES               13
3274 #define MAX_REQUEST_LINE_FONT1_LEN      7
3275 #define MAX_REQUEST_LINE_FONT2_LEN      10
3276
3277 static int RequestHandleEvents(unsigned int req_state)
3278 {
3279   int last_game_status = game_status;   /* save current game status */
3280   int result;
3281   int mx, my;
3282
3283   button_status = MB_RELEASED;
3284
3285   request_gadget_id = -1;
3286   result = -1;
3287
3288   while (result < 0)
3289   {
3290     if (PendingEvent())
3291     {
3292       Event event;
3293
3294       while (NextValidEvent(&event))
3295       {
3296         switch (event.type)
3297         {
3298           case EVENT_BUTTONPRESS:
3299           case EVENT_BUTTONRELEASE:
3300           case EVENT_MOTIONNOTIFY:
3301           {
3302             if (event.type == EVENT_MOTIONNOTIFY)
3303             {
3304               if (!button_status)
3305                 continue;
3306
3307               motion_status = TRUE;
3308               mx = ((MotionEvent *) &event)->x;
3309               my = ((MotionEvent *) &event)->y;
3310             }
3311             else
3312             {
3313               motion_status = FALSE;
3314               mx = ((ButtonEvent *) &event)->x;
3315               my = ((ButtonEvent *) &event)->y;
3316               if (event.type == EVENT_BUTTONPRESS)
3317                 button_status = ((ButtonEvent *) &event)->button;
3318               else
3319                 button_status = MB_RELEASED;
3320             }
3321
3322             /* this sets 'request_gadget_id' */
3323             HandleGadgets(mx, my, button_status);
3324
3325             switch (request_gadget_id)
3326             {
3327               case TOOL_CTRL_ID_YES:
3328                 result = TRUE;
3329                 break;
3330               case TOOL_CTRL_ID_NO:
3331                 result = FALSE;
3332                 break;
3333               case TOOL_CTRL_ID_CONFIRM:
3334                 result = TRUE | FALSE;
3335                 break;
3336
3337               case TOOL_CTRL_ID_PLAYER_1:
3338                 result = 1;
3339                 break;
3340               case TOOL_CTRL_ID_PLAYER_2:
3341                 result = 2;
3342                 break;
3343               case TOOL_CTRL_ID_PLAYER_3:
3344                 result = 3;
3345                 break;
3346               case TOOL_CTRL_ID_PLAYER_4:
3347                 result = 4;
3348                 break;
3349
3350               default:
3351                 break;
3352             }
3353
3354             break;
3355           }
3356
3357           case EVENT_KEYPRESS:
3358             switch (GetEventKey((KeyEvent *)&event, TRUE))
3359             {
3360               case KSYM_space:
3361                 if (req_state & REQ_CONFIRM)
3362                   result = 1;
3363                 break;
3364
3365               case KSYM_Return:
3366 #if defined(TARGET_SDL2)
3367               case KSYM_Menu:
3368 #endif
3369                 result = 1;
3370                 break;
3371
3372               case KSYM_Escape:
3373 #if defined(TARGET_SDL2)
3374               case KSYM_Back:
3375 #endif
3376                 result = 0;
3377                 break;
3378
3379               default:
3380                 break;
3381             }
3382
3383             if (req_state & REQ_PLAYER)
3384               result = 0;
3385             break;
3386
3387           case EVENT_KEYRELEASE:
3388             ClearPlayerAction();
3389             break;
3390
3391           default:
3392             HandleOtherEvents(&event);
3393             break;
3394         }
3395       }
3396     }
3397     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3398     {
3399       int joy = AnyJoystick();
3400
3401       if (joy & JOY_BUTTON_1)
3402         result = 1;
3403       else if (joy & JOY_BUTTON_2)
3404         result = 0;
3405     }
3406
3407     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3408     {
3409       HandleGameActions();
3410     }
3411     else
3412     {
3413       DoAnimation();
3414
3415       if (!PendingEvent())      /* delay only if no pending events */
3416         Delay(10);
3417     }
3418
3419     game_status = GAME_MODE_PSEUDO_DOOR;
3420
3421     BackToFront();
3422
3423     game_status = last_game_status;     /* restore current game status */
3424   }
3425
3426   return result;
3427 }
3428
3429 static boolean RequestDoor(char *text, unsigned int req_state)
3430 {
3431   unsigned int old_door_state;
3432   int last_game_status = game_status;   /* save current game status */
3433   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3434   int font_nr = FONT_TEXT_2;
3435   char *text_ptr;
3436   int result;
3437   int ty;
3438
3439   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3440   {
3441     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3442     font_nr = FONT_TEXT_1;
3443   }
3444
3445   if (game_status == GAME_MODE_PLAYING)
3446     BlitScreenToBitmap(backbuffer);
3447
3448   /* disable deactivated drawing when quick-loading level tape recording */
3449   if (tape.playing && tape.deactivate_display)
3450     TapeDeactivateDisplayOff(TRUE);
3451
3452   SetMouseCursor(CURSOR_DEFAULT);
3453
3454 #if defined(NETWORK_AVALIABLE)
3455   /* pause network game while waiting for request to answer */
3456   if (options.network &&
3457       game_status == GAME_MODE_PLAYING &&
3458       req_state & REQUEST_WAIT_FOR_INPUT)
3459     SendToServer_PausePlaying();
3460 #endif
3461
3462   old_door_state = GetDoorState();
3463
3464   /* simulate releasing mouse button over last gadget, if still pressed */
3465   if (button_status)
3466     HandleGadgets(-1, -1, 0);
3467
3468   UnmapAllGadgets();
3469
3470   /* draw released gadget before proceeding */
3471   // BackToFront();
3472
3473   if (old_door_state & DOOR_OPEN_1)
3474   {
3475     CloseDoor(DOOR_CLOSE_1);
3476
3477     /* save old door content */
3478     BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3479                0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3480   }
3481
3482   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3483   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3484
3485   /* clear door drawing field */
3486   DrawBackground(DX, DY, DXSIZE, DYSIZE);
3487
3488   /* force DOOR font inside door area */
3489   game_status = GAME_MODE_PSEUDO_DOOR;
3490
3491   /* write text for request */
3492   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3493   {
3494     char text_line[max_request_line_len + 1];
3495     int tx, tl, tc = 0;
3496
3497     if (!*text_ptr)
3498       break;
3499
3500     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3501     {
3502       tc = *(text_ptr + tx);
3503       // if (!tc || tc == ' ')
3504       if (!tc || tc == ' ' || tc == '?' || tc == '!')
3505         break;
3506     }
3507
3508     if ((tc == '?' || tc == '!') && tl == 0)
3509       tl = 1;
3510
3511     if (!tl)
3512     { 
3513       text_ptr++; 
3514       ty--; 
3515       continue; 
3516     }
3517
3518     strncpy(text_line, text_ptr, tl);
3519     text_line[tl] = 0;
3520
3521     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3522              DY + 8 + ty * (getFontHeight(font_nr) + 2),
3523              text_line, font_nr);
3524
3525     text_ptr += tl + (tc == ' ' ? 1 : 0);
3526     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3527   }
3528
3529   game_status = last_game_status;       /* restore current game status */
3530
3531   if (req_state & REQ_ASK)
3532   {
3533     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3534     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3535   }
3536   else if (req_state & REQ_CONFIRM)
3537   {
3538     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3539   }
3540   else if (req_state & REQ_PLAYER)
3541   {
3542     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3543     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3544     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3545     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3546   }
3547
3548   /* copy request gadgets to door backbuffer */
3549   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3550
3551   OpenDoor(DOOR_OPEN_1);
3552
3553   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3554   {
3555     if (game_status == GAME_MODE_PLAYING)
3556     {
3557       SetPanelBackground();
3558       SetDrawBackgroundMask(REDRAW_DOOR_1);
3559     }
3560     else
3561     {
3562       SetDrawBackgroundMask(REDRAW_FIELD);
3563     }
3564
3565     return FALSE;
3566   }
3567
3568   if (game_status != GAME_MODE_MAIN)
3569     InitAnimation();
3570
3571   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3572
3573   // ---------- handle request buttons ----------
3574   result = RequestHandleEvents(req_state);
3575
3576   if (game_status != GAME_MODE_MAIN)
3577     StopAnimation();
3578
3579   UnmapToolButtons();
3580
3581   if (!(req_state & REQ_STAY_OPEN))
3582   {
3583     CloseDoor(DOOR_CLOSE_1);
3584
3585     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3586         (req_state & REQ_REOPEN))
3587       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3588   }
3589
3590   RemapAllGadgets();
3591
3592   if (game_status == GAME_MODE_PLAYING)
3593   {
3594     SetPanelBackground();
3595     SetDrawBackgroundMask(REDRAW_DOOR_1);
3596   }
3597   else
3598   {
3599     SetDrawBackgroundMask(REDRAW_FIELD);
3600   }
3601
3602 #if defined(NETWORK_AVALIABLE)
3603   /* continue network game after request */
3604   if (options.network &&
3605       game_status == GAME_MODE_PLAYING &&
3606       req_state & REQUEST_WAIT_FOR_INPUT)
3607     SendToServer_ContinuePlaying();
3608 #endif
3609
3610   /* restore deactivated drawing when quick-loading level tape recording */
3611   if (tape.playing && tape.deactivate_display)
3612     TapeDeactivateDisplayOn();
3613
3614   return result;
3615 }
3616
3617 static boolean RequestEnvelope(char *text, unsigned int req_state)
3618 {
3619   int result;
3620
3621   if (game_status == GAME_MODE_PLAYING)
3622     BlitScreenToBitmap(backbuffer);
3623
3624   /* disable deactivated drawing when quick-loading level tape recording */
3625   if (tape.playing && tape.deactivate_display)
3626     TapeDeactivateDisplayOff(TRUE);
3627
3628   SetMouseCursor(CURSOR_DEFAULT);
3629
3630 #if defined(NETWORK_AVALIABLE)
3631   /* pause network game while waiting for request to answer */
3632   if (options.network &&
3633       game_status == GAME_MODE_PLAYING &&
3634       req_state & REQUEST_WAIT_FOR_INPUT)
3635     SendToServer_PausePlaying();
3636 #endif
3637
3638   /* simulate releasing mouse button over last gadget, if still pressed */
3639   if (button_status)
3640     HandleGadgets(-1, -1, 0);
3641
3642   UnmapAllGadgets();
3643
3644   // (replace with setting corresponding request background)
3645   // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3646   // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3647
3648   /* clear door drawing field */
3649   // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3650
3651   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3652
3653   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3654   {
3655     if (game_status == GAME_MODE_PLAYING)
3656     {
3657       SetPanelBackground();
3658       SetDrawBackgroundMask(REDRAW_DOOR_1);
3659     }
3660     else
3661     {
3662       SetDrawBackgroundMask(REDRAW_FIELD);
3663     }
3664
3665     return FALSE;
3666   }
3667
3668   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3669
3670   // ---------- handle request buttons ----------
3671   result = RequestHandleEvents(req_state);
3672
3673   if (game_status != GAME_MODE_MAIN)
3674     StopAnimation();
3675
3676   UnmapToolButtons();
3677
3678   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3679
3680   RemapAllGadgets();
3681
3682   if (game_status == GAME_MODE_PLAYING)
3683   {
3684     SetPanelBackground();
3685     SetDrawBackgroundMask(REDRAW_DOOR_1);
3686   }
3687   else
3688   {
3689     SetDrawBackgroundMask(REDRAW_FIELD);
3690   }
3691
3692 #if defined(NETWORK_AVALIABLE)
3693   /* continue network game after request */
3694   if (options.network &&
3695       game_status == GAME_MODE_PLAYING &&
3696       req_state & REQUEST_WAIT_FOR_INPUT)
3697     SendToServer_ContinuePlaying();
3698 #endif
3699
3700   /* restore deactivated drawing when quick-loading level tape recording */
3701   if (tape.playing && tape.deactivate_display)
3702     TapeDeactivateDisplayOn();
3703
3704   return result;
3705 }
3706
3707 boolean Request(char *text, unsigned int req_state)
3708 {
3709   if (global.use_envelope_request)
3710     return RequestEnvelope(text, req_state);
3711   else
3712     return RequestDoor(text, req_state);
3713 }
3714
3715 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3716 {
3717   const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3718   const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3719   int compare_result;
3720
3721   if (dpo1->sort_priority != dpo2->sort_priority)
3722     compare_result = dpo1->sort_priority - dpo2->sort_priority;
3723   else
3724     compare_result = dpo1->nr - dpo2->nr;
3725
3726   return compare_result;
3727 }
3728
3729 void InitGraphicCompatibilityInfo_Doors()
3730 {
3731   struct
3732   {
3733     int door_token;
3734     int part_1, part_8;
3735     struct DoorInfo *door;
3736   }
3737   doors[] =
3738   {
3739     { DOOR_1,   IMG_DOOR_1_GFX_PART_1,  IMG_DOOR_1_GFX_PART_8,  &door_1 },
3740     { DOOR_2,   IMG_DOOR_2_GFX_PART_1,  IMG_DOOR_2_GFX_PART_8,  &door_2 },
3741
3742     { -1,       -1,                     -1,                     NULL    }
3743   };
3744   struct Rect door_rect_list[] =
3745   {
3746     { DX, DY, DXSIZE, DYSIZE },
3747     { VX, VY, VXSIZE, VYSIZE }
3748   };
3749   int i, j;
3750
3751   for (i = 0; doors[i].door_token != -1; i++)
3752   {
3753     int door_token = doors[i].door_token;
3754     int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3755     int part_1 = doors[i].part_1;
3756     int part_8 = doors[i].part_8;
3757     int part_2 = part_1 + 1;
3758     int part_3 = part_1 + 2;
3759     struct DoorInfo *door = doors[i].door;
3760     struct Rect *door_rect = &door_rect_list[door_index];
3761     boolean door_gfx_redefined = FALSE;
3762
3763     /* check if any door part graphic definitions have been redefined */
3764
3765     for (j = 0; door_part_controls[j].door_token != -1; j++)
3766     {
3767       struct DoorPartControlInfo *dpc = &door_part_controls[j];
3768       struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3769
3770       if (dpc->door_token == door_token && fi->redefined)
3771         door_gfx_redefined = TRUE;
3772     }
3773
3774     /* check for old-style door graphic/animation modifications */
3775
3776     if (!door_gfx_redefined)
3777     {
3778       if (door->anim_mode & ANIM_STATIC_PANEL)
3779       {
3780         door->panel.step_xoffset = 0;
3781         door->panel.step_yoffset = 0;
3782       }
3783
3784       if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3785       {
3786         struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3787         struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3788         int num_door_steps, num_panel_steps;
3789
3790         /* remove door part graphics other than the two default wings */
3791
3792         for (j = 0; door_part_controls[j].door_token != -1; j++)
3793         {
3794           struct DoorPartControlInfo *dpc = &door_part_controls[j];
3795           struct GraphicInfo *g = &graphic_info[dpc->graphic];
3796
3797           if (dpc->graphic >= part_3 &&
3798               dpc->graphic <= part_8)
3799             g->bitmap = NULL;
3800         }
3801
3802         /* set graphics and screen positions of the default wings */
3803
3804         g_part_1->width  = door_rect->width;
3805         g_part_1->height = door_rect->height;
3806         g_part_2->width  = door_rect->width;
3807         g_part_2->height = door_rect->height;
3808         g_part_2->src_x = door_rect->width;
3809         g_part_2->src_y = g_part_1->src_y;
3810
3811         door->part_2.x = door->part_1.x;
3812         door->part_2.y = door->part_1.y;
3813
3814         if (door->width != -1)
3815         {
3816           g_part_1->width = door->width;
3817           g_part_2->width = door->width;
3818
3819           // special treatment for graphics and screen position of right wing
3820           g_part_2->src_x += door_rect->width - door->width;
3821           door->part_2.x  += door_rect->width - door->width;
3822         }
3823
3824         if (door->height != -1)
3825         {
3826           g_part_1->height = door->height;
3827           g_part_2->height = door->height;
3828
3829           // special treatment for graphics and screen position of bottom wing
3830           g_part_2->src_y += door_rect->height - door->height;
3831           door->part_2.y  += door_rect->height - door->height;
3832         }
3833
3834         /* set animation delays for the default wings and panels */
3835
3836         door->part_1.step_delay = door->step_delay;
3837         door->part_2.step_delay = door->step_delay;
3838         door->panel.step_delay  = door->step_delay;
3839
3840         /* set animation draw order for the default wings */
3841
3842         door->part_1.sort_priority = 2; /* draw left wing over ... */
3843         door->part_2.sort_priority = 1; /*          ... right wing */
3844
3845         /* set animation draw offset for the default wings */
3846
3847         if (door->anim_mode & ANIM_HORIZONTAL)
3848         {
3849           door->part_1.step_xoffset = door->step_offset;
3850           door->part_1.step_yoffset = 0;
3851           door->part_2.step_xoffset = door->step_offset * -1;
3852           door->part_2.step_yoffset = 0;
3853
3854           num_door_steps = g_part_1->width / door->step_offset;
3855         }
3856         else    // ANIM_VERTICAL
3857         {
3858           door->part_1.step_xoffset = 0;
3859           door->part_1.step_yoffset = door->step_offset;
3860           door->part_2.step_xoffset = 0;
3861           door->part_2.step_yoffset = door->step_offset * -1;
3862
3863           num_door_steps = g_part_1->height / door->step_offset;
3864         }
3865
3866         /* set animation draw offset for the default panels */
3867
3868         if (door->step_offset > 1)
3869         {
3870           num_panel_steps = 2 * door_rect->height / door->step_offset;
3871           door->panel.start_step = num_panel_steps - num_door_steps;
3872           door->panel.start_step_closing = door->panel.start_step;
3873         }
3874         else
3875         {
3876           num_panel_steps = door_rect->height / door->step_offset;
3877           door->panel.start_step = num_panel_steps - num_door_steps / 2;
3878           door->panel.start_step_closing = door->panel.start_step;
3879           door->panel.step_delay *= 2;
3880         }
3881       }
3882     }
3883   }
3884 }
3885
3886 void InitDoors()
3887 {
3888   int i;
3889
3890   for (i = 0; door_part_controls[i].door_token != -1; i++)
3891   {
3892     struct DoorPartControlInfo *dpc = &door_part_controls[i];
3893     struct DoorPartOrderInfo *dpo = &door_part_order[i];
3894
3895     /* initialize "start_step_opening" and "start_step_closing", if needed */
3896     if (dpc->pos->start_step_opening == 0 &&
3897         dpc->pos->start_step_closing == 0)
3898     {
3899       // dpc->pos->start_step_opening = dpc->pos->start_step;
3900       dpc->pos->start_step_closing = dpc->pos->start_step;
3901     }
3902
3903     /* fill structure for door part draw order (sorted below) */
3904     dpo->nr = i;
3905     dpo->sort_priority = dpc->pos->sort_priority;
3906   }
3907
3908   /* sort door part controls according to sort_priority and graphic number */
3909   qsort(door_part_order, MAX_DOOR_PARTS,
3910         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3911 }
3912
3913 unsigned int OpenDoor(unsigned int door_state)
3914 {
3915   if (door_state & DOOR_COPY_BACK)
3916   {
3917     if (door_state & DOOR_OPEN_1)
3918       BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3919                  1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3920
3921     if (door_state & DOOR_OPEN_2)
3922       BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3923                  1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3924
3925     door_state &= ~DOOR_COPY_BACK;
3926   }
3927
3928   return MoveDoor(door_state);
3929 }
3930
3931 unsigned int CloseDoor(unsigned int door_state)
3932 {
3933   unsigned int old_door_state = GetDoorState();
3934
3935   if (!(door_state & DOOR_NO_COPY_BACK))
3936   {
3937     if (old_door_state & DOOR_OPEN_1)
3938       BlitBitmap(backbuffer, bitmap_db_door_1,
3939                  DX, DY, DXSIZE, DYSIZE, 0, 0);
3940
3941     if (old_door_state & DOOR_OPEN_2)
3942       BlitBitmap(backbuffer, bitmap_db_door_2,
3943                  VX, VY, VXSIZE, VYSIZE, 0, 0);
3944
3945     door_state &= ~DOOR_NO_COPY_BACK;
3946   }
3947
3948   return MoveDoor(door_state);
3949 }
3950
3951 unsigned int GetDoorState()
3952 {
3953   return MoveDoor(DOOR_GET_STATE);
3954 }
3955
3956 unsigned int SetDoorState(unsigned int door_state)
3957 {
3958   return MoveDoor(door_state | DOOR_SET_STATE);
3959 }
3960
3961 int euclid(int a, int b)
3962 {
3963   return (b ? euclid(b, a % b) : a);
3964 }
3965
3966 unsigned int MoveDoor(unsigned int door_state)
3967 {
3968   struct Rect door_rect_list[] =
3969   {
3970     { DX, DY, DXSIZE, DYSIZE },
3971     { VX, VY, VXSIZE, VYSIZE }
3972   };
3973   static int door1 = DOOR_OPEN_1;
3974   static int door2 = DOOR_CLOSE_2;
3975   unsigned int door_delay = 0;
3976   unsigned int door_delay_value;
3977   int i;
3978
3979   if (door_state == DOOR_GET_STATE)
3980     return (door1 | door2);
3981
3982   if (door_state & DOOR_SET_STATE)
3983   {
3984     if (door_state & DOOR_ACTION_1)
3985       door1 = door_state & DOOR_ACTION_1;
3986     if (door_state & DOOR_ACTION_2)
3987       door2 = door_state & DOOR_ACTION_2;
3988
3989     return (door1 | door2);
3990   }
3991
3992   if (!(door_state & DOOR_FORCE_REDRAW))
3993   {
3994     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3995       door_state &= ~DOOR_OPEN_1;
3996     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
3997       door_state &= ~DOOR_CLOSE_1;
3998     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
3999       door_state &= ~DOOR_OPEN_2;
4000     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4001       door_state &= ~DOOR_CLOSE_2;
4002   }
4003
4004   if (global.autoplay_leveldir)
4005   {
4006     door_state |= DOOR_NO_DELAY;
4007     door_state &= ~DOOR_CLOSE_ALL;
4008   }
4009
4010   if (game_status == GAME_MODE_EDITOR)
4011     door_state |= DOOR_NO_DELAY;
4012
4013   if (door_state & DOOR_ACTION)
4014   {
4015     boolean door_panel_drawn[NUM_DOORS];
4016     boolean panel_has_doors[NUM_DOORS];
4017     boolean door_part_skip[MAX_DOOR_PARTS];
4018     boolean door_part_done[MAX_DOOR_PARTS];
4019     boolean door_part_done_all;
4020     int num_steps[MAX_DOOR_PARTS];
4021     int max_move_delay = 0;     // delay for complete animations of all doors
4022     int max_step_delay = 0;     // delay (ms) between two animation frames
4023     int num_move_steps = 0;     // number of animation steps for all doors
4024     int max_move_delay_doors_only = 0;  // delay for doors only (no panel)
4025     int num_move_steps_doors_only = 0;  // steps for doors only (no panel)
4026     int current_move_delay = 0;
4027     int start = 0;
4028     int k;
4029
4030     for (i = 0; i < NUM_DOORS; i++)
4031       panel_has_doors[i] = FALSE;
4032
4033     for (i = 0; i < MAX_DOOR_PARTS; i++)
4034     {
4035       struct DoorPartControlInfo *dpc = &door_part_controls[i];
4036       struct GraphicInfo *g = &graphic_info[dpc->graphic];
4037       int door_token = dpc->door_token;
4038
4039       door_part_done[i] = FALSE;
4040       door_part_skip[i] = (!(door_state & door_token) ||
4041                            !g->bitmap);
4042     }
4043
4044     for (i = 0; i < MAX_DOOR_PARTS; i++)
4045     {
4046       int nr = door_part_order[i].nr;
4047       struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4048       struct DoorPartPosInfo *pos = dpc->pos;
4049       struct GraphicInfo *g = &graphic_info[dpc->graphic];
4050       int door_token = dpc->door_token;
4051       int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4052       boolean is_panel = DOOR_PART_IS_PANEL(nr);
4053       int step_xoffset = ABS(pos->step_xoffset);
4054       int step_yoffset = ABS(pos->step_yoffset);
4055       int step_delay = pos->step_delay;
4056       int current_door_state = door_state & door_token;
4057       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
4058       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4059       boolean part_opening = (is_panel ? door_closing : door_opening);
4060       int start_step = (part_opening ? pos->start_step_opening :
4061                         pos->start_step_closing);
4062       float move_xsize = (step_xoffset ? g->width  : 0);
4063       float move_ysize = (step_yoffset ? g->height : 0);
4064       int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4065       int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4066       int move_steps = (move_xsteps && move_ysteps ?
4067                         MIN(move_xsteps, move_ysteps) :
4068                         move_xsteps ? move_xsteps : move_ysteps) - start_step;
4069       int move_delay = move_steps * step_delay;
4070
4071       if (door_part_skip[nr])
4072         continue;
4073
4074       max_move_delay = MAX(max_move_delay, move_delay);
4075       max_step_delay = (max_step_delay == 0 ? step_delay :
4076                         euclid(max_step_delay, step_delay));
4077       num_steps[nr] = move_steps;
4078
4079       if (!is_panel)
4080       {
4081         max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4082
4083         panel_has_doors[door_index] = TRUE;
4084       }
4085     }
4086
4087     max_step_delay = MAX(1, max_step_delay);    // prevent division by zero
4088
4089     num_move_steps = max_move_delay / max_step_delay;
4090     num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4091
4092     door_delay_value = max_step_delay;
4093
4094     if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4095     {
4096       start = num_move_steps - 1;
4097     }
4098     else
4099     {
4100       /* opening door sound has priority over simultaneously closing door */
4101       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4102         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4103       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4104         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4105     }
4106
4107     for (k = start; k < num_move_steps; k++)
4108     {
4109       int last_frame = num_move_steps - 1;      // last frame of this "for" loop
4110
4111       door_part_done_all = TRUE;
4112
4113       for (i = 0; i < NUM_DOORS; i++)
4114         door_panel_drawn[i] = FALSE;
4115
4116       for (i = 0; i < MAX_DOOR_PARTS; i++)
4117       {
4118         int nr = door_part_order[i].nr;
4119         struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4120         struct DoorPartPosInfo *pos = dpc->pos;
4121         struct GraphicInfo *g = &graphic_info[dpc->graphic];
4122         int door_token = dpc->door_token;
4123         int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4124         boolean is_panel = DOOR_PART_IS_PANEL(nr);
4125         boolean is_panel_and_door_has_closed = FALSE;
4126         struct Rect *door_rect = &door_rect_list[door_index];
4127         Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4128                                   bitmap_db_door_2);
4129         Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4130         int current_door_state = door_state & door_token;
4131         boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
4132         boolean door_closing = !door_opening;
4133         boolean part_opening = (is_panel ? door_closing : door_opening);
4134         boolean part_closing = !part_opening;
4135         int start_step = (part_opening ? pos->start_step_opening :
4136                           pos->start_step_closing);
4137         int step_delay = pos->step_delay;
4138         int step_factor = step_delay / max_step_delay;
4139         int k1 = (step_factor ? k / step_factor + 1 : k);
4140         int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4141         int kk = MAX(0, k2);
4142         int g_src_x = 0;
4143         int g_src_y = 0;
4144         int src_x, src_y, src_xx, src_yy;
4145         int dst_x, dst_y, dst_xx, dst_yy;
4146         int width, height;
4147
4148         if (door_part_skip[nr])
4149           continue;
4150
4151         if (!(door_state & door_token))
4152           continue;
4153
4154         if (!g->bitmap)
4155           continue;
4156
4157         if (!is_panel)
4158         {
4159           int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4160           int kk_door = MAX(0, k2_door);
4161           int sync_frame = kk_door * door_delay_value;
4162           int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4163
4164           getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4165         }
4166
4167         // draw door panel
4168
4169         if (!door_panel_drawn[door_index])
4170         {
4171           ClearRectangle(drawto, door_rect->x, door_rect->y,
4172                          door_rect->width, door_rect->height);
4173
4174           door_panel_drawn[door_index] = TRUE;
4175         }
4176
4177         // draw opening or closing door parts
4178
4179         if (pos->step_xoffset < 0)      // door part on right side
4180         {
4181           src_xx = 0;
4182           dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4183           width = g->width;
4184
4185           if (dst_xx + width > door_rect->width)
4186             width = door_rect->width - dst_xx;
4187         }
4188         else                            // door part on left side
4189         {
4190           src_xx = 0;
4191           dst_xx = pos->x - kk * pos->step_xoffset;
4192
4193           if (dst_xx < 0)
4194           {
4195             src_xx = ABS(dst_xx);
4196             dst_xx = 0;
4197           }
4198
4199           width = g->width - src_xx;
4200
4201           // printf("::: k == %d [%d] \n", k, start_step);
4202         }
4203
4204         if (pos->step_yoffset < 0)      // door part on bottom side
4205         {
4206           src_yy = 0;
4207           dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4208           height = g->height;
4209
4210           if (dst_yy + height > door_rect->height)
4211             height = door_rect->height - dst_yy;
4212         }
4213         else                            // door part on top side
4214         {
4215           src_yy = 0;
4216           dst_yy = pos->y - kk * pos->step_yoffset;
4217
4218           if (dst_yy < 0)
4219           {
4220             src_yy = ABS(dst_yy);
4221             dst_yy = 0;
4222           }
4223
4224           height = g->height - src_yy;
4225         }
4226
4227         src_x = g_src_x + src_xx;
4228         src_y = g_src_y + src_yy;
4229
4230         dst_x = door_rect->x + dst_xx;
4231         dst_y = door_rect->y + dst_yy;
4232
4233         is_panel_and_door_has_closed =
4234           (is_panel &&
4235            door_closing &&
4236            panel_has_doors[door_index] &&
4237            k >= num_move_steps_doors_only - 1);
4238
4239         if (width  >= 0 && width  <= g->width &&
4240             height >= 0 && height <= g->height &&
4241             !is_panel_and_door_has_closed)
4242         {
4243           if (is_panel || !pos->draw_masked)
4244             BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4245                        dst_x, dst_y);
4246           else
4247             BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4248                              dst_x, dst_y);
4249         }
4250
4251         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4252
4253         if ((part_opening && (width < 0         || height < 0)) ||
4254             (part_closing && (width >= g->width && height >= g->height)))
4255           door_part_done[nr] = TRUE;
4256
4257         // continue door part animations, but not panel after door has closed
4258         if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4259           door_part_done_all = FALSE;
4260       }
4261
4262       if (!(door_state & DOOR_NO_DELAY))
4263       {
4264         BackToFront();
4265
4266         if (game_status == GAME_MODE_MAIN)
4267           DoAnimation();
4268
4269         SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4270
4271         current_move_delay += max_step_delay;
4272       }
4273
4274       if (door_part_done_all)
4275         break;
4276     }
4277   }
4278
4279   if (door_state & DOOR_ACTION_1)
4280     door1 = door_state & DOOR_ACTION_1;
4281   if (door_state & DOOR_ACTION_2)
4282     door2 = door_state & DOOR_ACTION_2;
4283
4284   return (door1 | door2);
4285 }
4286
4287 void DrawSpecialEditorDoor()
4288 {
4289   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4290   int top_border_width = gfx1->width;
4291   int top_border_height = gfx1->height;
4292   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4293   int ex = EX - outer_border;
4294   int ey = EY - outer_border;
4295   int vy = VY - outer_border;
4296   int exsize = EXSIZE + 2 * outer_border;
4297
4298   /* draw bigger level editor toolbox window */
4299   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4300              top_border_width, top_border_height, ex, ey - top_border_height);
4301   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4302              exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4303
4304   redraw_mask |= REDRAW_ALL;
4305 }
4306
4307 void UndrawSpecialEditorDoor()
4308 {
4309   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4310   int top_border_width = gfx1->width;
4311   int top_border_height = gfx1->height;
4312   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4313   int ex = EX - outer_border;
4314   int ey = EY - outer_border;
4315   int ey_top = ey - top_border_height;
4316   int exsize = EXSIZE + 2 * outer_border;
4317   int eysize = EYSIZE + 2 * outer_border;
4318
4319   /* draw normal tape recorder window */
4320   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4321   {
4322     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4323                ex, ey_top, top_border_width, top_border_height,
4324                ex, ey_top);
4325     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4326                ex, ey, exsize, eysize, ex, ey);
4327   }
4328   else
4329   {
4330     // if screen background is set to "[NONE]", clear editor toolbox window
4331     ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4332     ClearRectangle(drawto, ex, ey, exsize, eysize);
4333   }
4334
4335   redraw_mask |= REDRAW_ALL;
4336 }
4337
4338
4339 /* ---------- new tool button stuff ---------------------------------------- */
4340
4341 static struct
4342 {
4343   int graphic;
4344   struct TextPosInfo *pos;
4345   int gadget_id;
4346   char *infotext;
4347 } toolbutton_info[NUM_TOOL_BUTTONS] =
4348 {
4349   {
4350     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
4351     TOOL_CTRL_ID_YES,                   "yes"
4352   },
4353   {
4354     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
4355     TOOL_CTRL_ID_NO,                    "no"
4356   },
4357   {
4358     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
4359     TOOL_CTRL_ID_CONFIRM,               "confirm"
4360   },
4361   {
4362     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
4363     TOOL_CTRL_ID_PLAYER_1,              "player 1"
4364   },
4365   {
4366     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
4367     TOOL_CTRL_ID_PLAYER_2,              "player 2"
4368   },
4369   {
4370     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
4371     TOOL_CTRL_ID_PLAYER_3,              "player 3"
4372   },
4373   {
4374     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
4375     TOOL_CTRL_ID_PLAYER_4,              "player 4"
4376   }
4377 };
4378
4379 void CreateToolButtons()
4380 {
4381   int i;
4382
4383   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4384   {
4385     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4386     struct TextPosInfo *pos = toolbutton_info[i].pos;
4387     struct GadgetInfo *gi;
4388     Bitmap *deco_bitmap = None;
4389     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4390     unsigned int event_mask = GD_EVENT_RELEASED;
4391     int dx = DX;
4392     int dy = DY;
4393     int gd_x = gfx->src_x;
4394     int gd_y = gfx->src_y;
4395     int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4396     int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4397     int id = i;
4398
4399     if (global.use_envelope_request)
4400       setRequestPosition(&dx, &dy, TRUE);
4401
4402     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4403     {
4404       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4405
4406       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4407                             pos->size, &deco_bitmap, &deco_x, &deco_y);
4408       deco_xpos = (gfx->width  - pos->size) / 2;
4409       deco_ypos = (gfx->height - pos->size) / 2;
4410     }
4411
4412     gi = CreateGadget(GDI_CUSTOM_ID, id,
4413                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
4414                       GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4415                       GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4416                       GDI_WIDTH, gfx->width,
4417                       GDI_HEIGHT, gfx->height,
4418                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4419                       GDI_STATE, GD_BUTTON_UNPRESSED,
4420                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4421                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4422                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4423                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4424                       GDI_DECORATION_SIZE, pos->size, pos->size,
4425                       GDI_DECORATION_SHIFTING, 1, 1,
4426                       GDI_DIRECT_DRAW, FALSE,
4427                       GDI_EVENT_MASK, event_mask,
4428                       GDI_CALLBACK_ACTION, HandleToolButtons,
4429                       GDI_END);
4430
4431     if (gi == NULL)
4432       Error(ERR_EXIT, "cannot create gadget");
4433
4434     tool_gadget[id] = gi;
4435   }
4436 }
4437
4438 void FreeToolButtons()
4439 {
4440   int i;
4441
4442   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4443     FreeGadget(tool_gadget[i]);
4444 }
4445
4446 static void UnmapToolButtons()
4447 {
4448   int i;
4449
4450   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4451     UnmapGadget(tool_gadget[i]);
4452 }
4453
4454 static void HandleToolButtons(struct GadgetInfo *gi)
4455 {
4456   request_gadget_id = gi->custom_id;
4457 }
4458
4459 static struct Mapping_EM_to_RND_object
4460 {
4461   int element_em;
4462   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
4463   boolean is_backside;                  /* backside of moving element */
4464
4465   int element_rnd;
4466   int action;
4467   int direction;
4468 }
4469 em_object_mapping_list[] =
4470 {
4471   {
4472     Xblank,                             TRUE,   FALSE,
4473     EL_EMPTY,                           -1, -1
4474   },
4475   {
4476     Yacid_splash_eB,                    FALSE,  FALSE,
4477     EL_ACID_SPLASH_RIGHT,               -1, -1
4478   },
4479   {
4480     Yacid_splash_wB,                    FALSE,  FALSE,
4481     EL_ACID_SPLASH_LEFT,                -1, -1
4482   },
4483
4484 #ifdef EM_ENGINE_BAD_ROLL
4485   {
4486     Xstone_force_e,                     FALSE,  FALSE,
4487     EL_ROCK,                            -1, MV_BIT_RIGHT
4488   },
4489   {
4490     Xstone_force_w,                     FALSE,  FALSE,
4491     EL_ROCK,                            -1, MV_BIT_LEFT
4492   },
4493   {
4494     Xnut_force_e,                       FALSE,  FALSE,
4495     EL_NUT,                             -1, MV_BIT_RIGHT
4496   },
4497   {
4498     Xnut_force_w,                       FALSE,  FALSE,
4499     EL_NUT,                             -1, MV_BIT_LEFT
4500   },
4501   {
4502     Xspring_force_e,                    FALSE,  FALSE,
4503     EL_SPRING,                          -1, MV_BIT_RIGHT
4504   },
4505   {
4506     Xspring_force_w,                    FALSE,  FALSE,
4507     EL_SPRING,                          -1, MV_BIT_LEFT
4508   },
4509   {
4510     Xemerald_force_e,                   FALSE,  FALSE,
4511     EL_EMERALD,                         -1, MV_BIT_RIGHT
4512   },
4513   {
4514     Xemerald_force_w,                   FALSE,  FALSE,
4515     EL_EMERALD,                         -1, MV_BIT_LEFT
4516   },
4517   {
4518     Xdiamond_force_e,                   FALSE,  FALSE,
4519     EL_DIAMOND,                         -1, MV_BIT_RIGHT
4520   },
4521   {
4522     Xdiamond_force_w,                   FALSE,  FALSE,
4523     EL_DIAMOND,                         -1, MV_BIT_LEFT
4524   },
4525   {
4526     Xbomb_force_e,                      FALSE,  FALSE,
4527     EL_BOMB,                            -1, MV_BIT_RIGHT
4528   },
4529   {
4530     Xbomb_force_w,                      FALSE,  FALSE,
4531     EL_BOMB,                            -1, MV_BIT_LEFT
4532   },
4533 #endif  /* EM_ENGINE_BAD_ROLL */
4534
4535   {
4536     Xstone,                             TRUE,   FALSE,
4537     EL_ROCK,                            -1, -1
4538   },
4539   {
4540     Xstone_pause,                       FALSE,  FALSE,
4541     EL_ROCK,                            -1, -1
4542   },
4543   {
4544     Xstone_fall,                        FALSE,  FALSE,
4545     EL_ROCK,                            -1, -1
4546   },
4547   {
4548     Ystone_s,                           FALSE,  FALSE,
4549     EL_ROCK,                            ACTION_FALLING, -1
4550   },
4551   {
4552     Ystone_sB,                          FALSE,  TRUE,
4553     EL_ROCK,                            ACTION_FALLING, -1
4554   },
4555   {
4556     Ystone_e,                           FALSE,  FALSE,
4557     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4558   },
4559   {
4560     Ystone_eB,                          FALSE,  TRUE,
4561     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
4562   },
4563   {
4564     Ystone_w,                           FALSE,  FALSE,
4565     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4566   },
4567   {
4568     Ystone_wB,                          FALSE,  TRUE,
4569     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
4570   },
4571   {
4572     Xnut,                               TRUE,   FALSE,
4573     EL_NUT,                             -1, -1
4574   },
4575   {
4576     Xnut_pause,                         FALSE,  FALSE,
4577     EL_NUT,                             -1, -1
4578   },
4579   {
4580     Xnut_fall,                          FALSE,  FALSE,
4581     EL_NUT,                             -1, -1
4582   },
4583   {
4584     Ynut_s,                             FALSE,  FALSE,
4585     EL_NUT,                             ACTION_FALLING, -1
4586   },
4587   {
4588     Ynut_sB,                            FALSE,  TRUE,
4589     EL_NUT,                             ACTION_FALLING, -1
4590   },
4591   {
4592     Ynut_e,                             FALSE,  FALSE,
4593     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4594   },
4595   {
4596     Ynut_eB,                            FALSE,  TRUE,
4597     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
4598   },
4599   {
4600     Ynut_w,                             FALSE,  FALSE,
4601     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4602   },
4603   {
4604     Ynut_wB,                            FALSE,  TRUE,
4605     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
4606   },
4607   {
4608     Xbug_n,                             TRUE,   FALSE,
4609     EL_BUG_UP,                          -1, -1
4610   },
4611   {
4612     Xbug_e,                             TRUE,   FALSE,
4613     EL_BUG_RIGHT,                       -1, -1
4614   },
4615   {
4616     Xbug_s,                             TRUE,   FALSE,
4617     EL_BUG_DOWN,                        -1, -1
4618   },
4619   {
4620     Xbug_w,                             TRUE,   FALSE,
4621     EL_BUG_LEFT,                        -1, -1
4622   },
4623   {
4624     Xbug_gon,                           FALSE,  FALSE,
4625     EL_BUG_UP,                          -1, -1
4626   },
4627   {
4628     Xbug_goe,                           FALSE,  FALSE,
4629     EL_BUG_RIGHT,                       -1, -1
4630   },
4631   {
4632     Xbug_gos,                           FALSE,  FALSE,
4633     EL_BUG_DOWN,                        -1, -1
4634   },
4635   {
4636     Xbug_gow,                           FALSE,  FALSE,
4637     EL_BUG_LEFT,                        -1, -1
4638   },
4639   {
4640     Ybug_n,                             FALSE,  FALSE,
4641     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4642   },
4643   {
4644     Ybug_nB,                            FALSE,  TRUE,
4645     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
4646   },
4647   {
4648     Ybug_e,                             FALSE,  FALSE,
4649     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4650   },
4651   {
4652     Ybug_eB,                            FALSE,  TRUE,
4653     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
4654   },
4655   {
4656     Ybug_s,                             FALSE,  FALSE,
4657     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4658   },
4659   {
4660     Ybug_sB,                            FALSE,  TRUE,
4661     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
4662   },
4663   {
4664     Ybug_w,                             FALSE,  FALSE,
4665     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4666   },
4667   {
4668     Ybug_wB,                            FALSE,  TRUE,
4669     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
4670   },
4671   {
4672     Ybug_w_n,                           FALSE,  FALSE,
4673     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4674   },
4675   {
4676     Ybug_n_e,                           FALSE,  FALSE,
4677     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4678   },
4679   {
4680     Ybug_e_s,                           FALSE,  FALSE,
4681     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4682   },
4683   {
4684     Ybug_s_w,                           FALSE,  FALSE,
4685     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4686   },
4687   {
4688     Ybug_e_n,                           FALSE,  FALSE,
4689     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4690   },
4691   {
4692     Ybug_s_e,                           FALSE,  FALSE,
4693     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4694   },
4695   {
4696     Ybug_w_s,                           FALSE,  FALSE,
4697     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4698   },
4699   {
4700     Ybug_n_w,                           FALSE,  FALSE,
4701     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4702   },
4703   {
4704     Ybug_stone,                         FALSE,  FALSE,
4705     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
4706   },
4707   {
4708     Ybug_spring,                        FALSE,  FALSE,
4709     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
4710   },
4711   {
4712     Xtank_n,                            TRUE,   FALSE,
4713     EL_SPACESHIP_UP,                    -1, -1
4714   },
4715   {
4716     Xtank_e,                            TRUE,   FALSE,
4717     EL_SPACESHIP_RIGHT,                 -1, -1
4718   },
4719   {
4720     Xtank_s,                            TRUE,   FALSE,
4721     EL_SPACESHIP_DOWN,                  -1, -1
4722   },
4723   {
4724     Xtank_w,                            TRUE,   FALSE,
4725     EL_SPACESHIP_LEFT,                  -1, -1
4726   },
4727   {
4728     Xtank_gon,                          FALSE,  FALSE,
4729     EL_SPACESHIP_UP,                    -1, -1
4730   },
4731   {
4732     Xtank_goe,                          FALSE,  FALSE,
4733     EL_SPACESHIP_RIGHT,                 -1, -1
4734   },
4735   {
4736     Xtank_gos,                          FALSE,  FALSE,
4737     EL_SPACESHIP_DOWN,                  -1, -1
4738   },
4739   {
4740     Xtank_gow,                          FALSE,  FALSE,
4741     EL_SPACESHIP_LEFT,                  -1, -1
4742   },
4743   {
4744     Ytank_n,                            FALSE,  FALSE,
4745     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4746   },
4747   {
4748     Ytank_nB,                           FALSE,  TRUE,
4749     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
4750   },
4751   {
4752     Ytank_e,                            FALSE,  FALSE,
4753     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4754   },
4755   {
4756     Ytank_eB,                           FALSE,  TRUE,
4757     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
4758   },
4759   {
4760     Ytank_s,                            FALSE,  FALSE,
4761     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4762   },
4763   {
4764     Ytank_sB,                           FALSE,  TRUE,
4765     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
4766   },
4767   {
4768     Ytank_w,                            FALSE,  FALSE,
4769     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4770   },
4771   {
4772     Ytank_wB,                           FALSE,  TRUE,
4773     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
4774   },
4775   {
4776     Ytank_w_n,                          FALSE,  FALSE,
4777     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4778   },
4779   {
4780     Ytank_n_e,                          FALSE,  FALSE,
4781     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4782   },
4783   {
4784     Ytank_e_s,                          FALSE,  FALSE,
4785     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4786   },
4787   {
4788     Ytank_s_w,                          FALSE,  FALSE,
4789     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4790   },
4791   {
4792     Ytank_e_n,                          FALSE,  FALSE,
4793     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4794   },
4795   {
4796     Ytank_s_e,                          FALSE,  FALSE,
4797     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4798   },
4799   {
4800     Ytank_w_s,                          FALSE,  FALSE,
4801     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4802   },
4803   {
4804     Ytank_n_w,                          FALSE,  FALSE,
4805     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4806   },
4807   {
4808     Ytank_stone,                        FALSE,  FALSE,
4809     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
4810   },
4811   {
4812     Ytank_spring,                       FALSE,  FALSE,
4813     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
4814   },
4815   {
4816     Xandroid,                           TRUE,   FALSE,
4817     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
4818   },
4819   {
4820     Xandroid_1_n,                       FALSE,  FALSE,
4821     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4822   },
4823   {
4824     Xandroid_2_n,                       FALSE,  FALSE,
4825     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
4826   },
4827   {
4828     Xandroid_1_e,                       FALSE,  FALSE,
4829     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4830   },
4831   {
4832     Xandroid_2_e,                       FALSE,  FALSE,
4833     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
4834   },
4835   {
4836     Xandroid_1_w,                       FALSE,  FALSE,
4837     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4838   },
4839   {
4840     Xandroid_2_w,                       FALSE,  FALSE,
4841     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
4842   },
4843   {
4844     Xandroid_1_s,                       FALSE,  FALSE,
4845     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4846   },
4847   {
4848     Xandroid_2_s,                       FALSE,  FALSE,
4849     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
4850   },
4851   {
4852     Yandroid_n,                         FALSE,  FALSE,
4853     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4854   },
4855   {
4856     Yandroid_nB,                        FALSE,  TRUE,
4857     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
4858   },
4859   {
4860     Yandroid_ne,                        FALSE,  FALSE,
4861     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
4862   },
4863   {
4864     Yandroid_neB,                       FALSE,  TRUE,
4865     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
4866   },
4867   {
4868     Yandroid_e,                         FALSE,  FALSE,
4869     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4870   },
4871   {
4872     Yandroid_eB,                        FALSE,  TRUE,
4873     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
4874   },
4875   {
4876     Yandroid_se,                        FALSE,  FALSE,
4877     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
4878   },
4879   {
4880     Yandroid_seB,                       FALSE,  TRUE,
4881     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4882   },
4883   {
4884     Yandroid_s,                         FALSE,  FALSE,
4885     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4886   },
4887   {
4888     Yandroid_sB,                        FALSE,  TRUE,
4889     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
4890   },
4891   {
4892     Yandroid_sw,                        FALSE,  FALSE,
4893     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
4894   },
4895   {
4896     Yandroid_swB,                       FALSE,  TRUE,
4897     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
4898   },
4899   {
4900     Yandroid_w,                         FALSE,  FALSE,
4901     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4902   },
4903   {
4904     Yandroid_wB,                        FALSE,  TRUE,
4905     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
4906   },
4907   {
4908     Yandroid_nw,                        FALSE,  FALSE,
4909     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
4910   },
4911   {
4912     Yandroid_nwB,                       FALSE,  TRUE,
4913     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
4914   },
4915   {
4916     Xspring,                            TRUE,   FALSE,
4917     EL_SPRING,                          -1, -1
4918   },
4919   {
4920     Xspring_pause,                      FALSE,  FALSE,
4921     EL_SPRING,                          -1, -1
4922   },
4923   {
4924     Xspring_e,                          FALSE,  FALSE,
4925     EL_SPRING,                          -1, -1
4926   },
4927   {
4928     Xspring_w,                          FALSE,  FALSE,
4929     EL_SPRING,                          -1, -1
4930   },
4931   {
4932     Xspring_fall,                       FALSE,  FALSE,
4933     EL_SPRING,                          -1, -1
4934   },
4935   {
4936     Yspring_s,                          FALSE,  FALSE,
4937     EL_SPRING,                          ACTION_FALLING, -1
4938   },
4939   {
4940     Yspring_sB,                         FALSE,  TRUE,
4941     EL_SPRING,                          ACTION_FALLING, -1
4942   },
4943   {
4944     Yspring_e,                          FALSE,  FALSE,
4945     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4946   },
4947   {
4948     Yspring_eB,                         FALSE,  TRUE,
4949     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
4950   },
4951   {
4952     Yspring_w,                          FALSE,  FALSE,
4953     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4954   },
4955   {
4956     Yspring_wB,                         FALSE,  TRUE,
4957     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
4958   },
4959   {
4960     Yspring_kill_e,                     FALSE,  FALSE,
4961     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4962   },
4963   {
4964     Yspring_kill_eB,                    FALSE,  TRUE,
4965     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
4966   },
4967   {
4968     Yspring_kill_w,                     FALSE,  FALSE,
4969     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4970   },
4971   {
4972     Yspring_kill_wB,                    FALSE,  TRUE,
4973     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
4974   },
4975   {
4976     Xeater_n,                           TRUE,   FALSE,
4977     EL_YAMYAM_UP,                       -1, -1
4978   },
4979   {
4980     Xeater_e,                           TRUE,   FALSE,
4981     EL_YAMYAM_RIGHT,                    -1, -1
4982   },
4983   {
4984     Xeater_w,                           TRUE,   FALSE,
4985     EL_YAMYAM_LEFT,                     -1, -1
4986   },
4987   {
4988     Xeater_s,                           TRUE,   FALSE,
4989     EL_YAMYAM_DOWN,                     -1, -1
4990   },
4991   {
4992     Yeater_n,                           FALSE,  FALSE,
4993     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4994   },
4995   {
4996     Yeater_nB,                          FALSE,  TRUE,
4997     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
4998   },
4999   {
5000     Yeater_e,                           FALSE,  FALSE,
5001     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5002   },
5003   {
5004     Yeater_eB,                          FALSE,  TRUE,
5005     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
5006   },
5007   {
5008     Yeater_s,                           FALSE,  FALSE,
5009     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5010   },
5011   {
5012     Yeater_sB,                          FALSE,  TRUE,
5013     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
5014   },
5015   {
5016     Yeater_w,                           FALSE,  FALSE,
5017     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5018   },
5019   {
5020     Yeater_wB,                          FALSE,  TRUE,
5021     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
5022   },
5023   {
5024     Yeater_stone,                       FALSE,  FALSE,
5025     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
5026   },
5027   {
5028     Yeater_spring,                      FALSE,  FALSE,
5029     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
5030   },
5031   {
5032     Xalien,                             TRUE,   FALSE,
5033     EL_ROBOT,                           -1, -1
5034   },
5035   {
5036     Xalien_pause,                       FALSE,  FALSE,
5037     EL_ROBOT,                           -1, -1
5038   },
5039   {
5040     Yalien_n,                           FALSE,  FALSE,
5041     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5042   },
5043   {
5044     Yalien_nB,                          FALSE,  TRUE,
5045     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
5046   },
5047   {
5048     Yalien_e,                           FALSE,  FALSE,
5049     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5050   },
5051   {
5052     Yalien_eB,                          FALSE,  TRUE,
5053     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
5054   },
5055   {
5056     Yalien_s,                           FALSE,  FALSE,
5057     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5058   },
5059   {
5060     Yalien_sB,                          FALSE,  TRUE,
5061     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
5062   },
5063   {
5064     Yalien_w,                           FALSE,  FALSE,
5065     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5066   },
5067   {
5068     Yalien_wB,                          FALSE,  TRUE,
5069     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
5070   },
5071   {
5072     Yalien_stone,                       FALSE,  FALSE,
5073     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
5074   },
5075   {
5076     Yalien_spring,                      FALSE,  FALSE,
5077     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
5078   },
5079   {
5080     Xemerald,                           TRUE,   FALSE,
5081     EL_EMERALD,                         -1, -1
5082   },
5083   {
5084     Xemerald_pause,                     FALSE,  FALSE,
5085     EL_EMERALD,                         -1, -1
5086   },
5087   {
5088     Xemerald_fall,                      FALSE,  FALSE,
5089     EL_EMERALD,                         -1, -1
5090   },
5091   {
5092     Xemerald_shine,                     FALSE,  FALSE,
5093     EL_EMERALD,                         ACTION_TWINKLING, -1
5094   },
5095   {
5096     Yemerald_s,                         FALSE,  FALSE,
5097     EL_EMERALD,                         ACTION_FALLING, -1
5098   },
5099   {
5100     Yemerald_sB,                        FALSE,  TRUE,
5101     EL_EMERALD,                         ACTION_FALLING, -1
5102   },
5103   {
5104     Yemerald_e,                         FALSE,  FALSE,
5105     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5106   },
5107   {
5108     Yemerald_eB,                        FALSE,  TRUE,
5109     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
5110   },
5111   {
5112     Yemerald_w,                         FALSE,  FALSE,
5113     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5114   },
5115   {
5116     Yemerald_wB,                        FALSE,  TRUE,
5117     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
5118   },
5119   {
5120     Yemerald_eat,                       FALSE,  FALSE,
5121     EL_EMERALD,                         ACTION_COLLECTING, -1
5122   },
5123   {
5124     Yemerald_stone,                     FALSE,  FALSE,
5125     EL_NUT,                             ACTION_BREAKING, -1
5126   },
5127   {
5128     Xdiamond,                           TRUE,   FALSE,
5129     EL_DIAMOND,                         -1, -1
5130   },
5131   {
5132     Xdiamond_pause,                     FALSE,  FALSE,
5133     EL_DIAMOND,                         -1, -1
5134   },
5135   {
5136     Xdiamond_fall,                      FALSE,  FALSE,
5137     EL_DIAMOND,                         -1, -1
5138   },
5139   {
5140     Xdiamond_shine,                     FALSE,  FALSE,
5141     EL_DIAMOND,                         ACTION_TWINKLING, -1
5142   },
5143   {
5144     Ydiamond_s,                         FALSE,  FALSE,
5145     EL_DIAMOND,                         ACTION_FALLING, -1
5146   },
5147   {
5148     Ydiamond_sB,                        FALSE,  TRUE,
5149     EL_DIAMOND,                         ACTION_FALLING, -1
5150   },
5151   {
5152     Ydiamond_e,                         FALSE,  FALSE,
5153     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5154   },
5155   {
5156     Ydiamond_eB,                        FALSE,  TRUE,
5157     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
5158   },
5159   {
5160     Ydiamond_w,                         FALSE,  FALSE,
5161     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5162   },
5163   {
5164     Ydiamond_wB,                        FALSE,  TRUE,
5165     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
5166   },
5167   {
5168     Ydiamond_eat,                       FALSE,  FALSE,
5169     EL_DIAMOND,                         ACTION_COLLECTING, -1
5170   },
5171   {
5172     Ydiamond_stone,                     FALSE,  FALSE,
5173     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
5174   },
5175   {
5176     Xdrip_fall,                         TRUE,   FALSE,
5177     EL_AMOEBA_DROP,                     -1, -1
5178   },
5179   {
5180     Xdrip_stretch,                      FALSE,  FALSE,
5181     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5182   },
5183   {
5184     Xdrip_stretchB,                     FALSE,  TRUE,
5185     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5186   },
5187   {
5188     Xdrip_eat,                          FALSE,  FALSE,
5189     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
5190   },
5191   {
5192     Ydrip_s1,                           FALSE,  FALSE,
5193     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5194   },
5195   {
5196     Ydrip_s1B,                          FALSE,  TRUE,
5197     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5198   },
5199   {
5200     Ydrip_s2,                           FALSE,  FALSE,
5201     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5202   },
5203   {
5204     Ydrip_s2B,                          FALSE,  TRUE,
5205     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
5206   },
5207   {
5208     Xbomb,                              TRUE,   FALSE,
5209     EL_BOMB,                            -1, -1
5210   },
5211   {
5212     Xbomb_pause,                        FALSE,  FALSE,
5213     EL_BOMB,                            -1, -1
5214   },
5215   {
5216     Xbomb_fall,                         FALSE,  FALSE,
5217     EL_BOMB,                            -1, -1
5218   },
5219   {
5220     Ybomb_s,                            FALSE,  FALSE,
5221     EL_BOMB,                            ACTION_FALLING, -1
5222   },
5223   {
5224     Ybomb_sB,                           FALSE,  TRUE,
5225     EL_BOMB,                            ACTION_FALLING, -1
5226   },
5227   {
5228     Ybomb_e,                            FALSE,  FALSE,
5229     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5230   },
5231   {
5232     Ybomb_eB,                           FALSE,  TRUE,
5233     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
5234   },
5235   {
5236     Ybomb_w,                            FALSE,  FALSE,
5237     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5238   },
5239   {
5240     Ybomb_wB,                           FALSE,  TRUE,
5241     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
5242   },
5243   {
5244     Ybomb_eat,                          FALSE,  FALSE,
5245     EL_BOMB,                            ACTION_ACTIVATING, -1
5246   },
5247   {
5248     Xballoon,                           TRUE,   FALSE,
5249     EL_BALLOON,                         -1, -1
5250   },
5251   {
5252     Yballoon_n,                         FALSE,  FALSE,
5253     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5254   },
5255   {
5256     Yballoon_nB,                        FALSE,  TRUE,
5257     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
5258   },
5259   {
5260     Yballoon_e,                         FALSE,  FALSE,
5261     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5262   },
5263   {
5264     Yballoon_eB,                        FALSE,  TRUE,
5265     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
5266   },
5267   {
5268     Yballoon_s,                         FALSE,  FALSE,
5269     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5270   },
5271   {
5272     Yballoon_sB,                        FALSE,  TRUE,
5273     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
5274   },
5275   {
5276     Yballoon_w,                         FALSE,  FALSE,
5277     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5278   },
5279   {
5280     Yballoon_wB,                        FALSE,  TRUE,
5281     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
5282   },
5283   {
5284     Xgrass,                             TRUE,   FALSE,
5285     EL_EMC_GRASS,                       -1, -1
5286   },
5287   {
5288     Ygrass_nB,                          FALSE,  FALSE,
5289     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
5290   },
5291   {
5292     Ygrass_eB,                          FALSE,  FALSE,
5293     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
5294   },
5295   {
5296     Ygrass_sB,                          FALSE,  FALSE,
5297     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
5298   },
5299   {
5300     Ygrass_wB,                          FALSE,  FALSE,
5301     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
5302   },
5303   {
5304     Xdirt,                              TRUE,   FALSE,
5305     EL_SAND,                            -1, -1
5306   },
5307   {
5308     Ydirt_nB,                           FALSE,  FALSE,
5309     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
5310   },
5311   {
5312     Ydirt_eB,                           FALSE,  FALSE,
5313     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
5314   },
5315   {
5316     Ydirt_sB,                           FALSE,  FALSE,
5317     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
5318   },
5319   {
5320     Ydirt_wB,                           FALSE,  FALSE,
5321     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
5322   },
5323   {
5324     Xacid_ne,                           TRUE,   FALSE,
5325     EL_ACID_POOL_TOPRIGHT,              -1, -1
5326   },
5327   {
5328     Xacid_se,                           TRUE,   FALSE,
5329     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
5330   },
5331   {
5332     Xacid_s,                            TRUE,   FALSE,
5333     EL_ACID_POOL_BOTTOM,                -1, -1
5334   },
5335   {
5336     Xacid_sw,                           TRUE,   FALSE,
5337     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
5338   },
5339   {
5340     Xacid_nw,                           TRUE,   FALSE,
5341     EL_ACID_POOL_TOPLEFT,               -1, -1
5342   },
5343   {
5344     Xacid_1,                            TRUE,   FALSE,
5345     EL_ACID,                            -1, -1
5346   },
5347   {
5348     Xacid_2,                            FALSE,  FALSE,
5349     EL_ACID,                            -1, -1
5350   },
5351   {
5352     Xacid_3,                            FALSE,  FALSE,
5353     EL_ACID,                            -1, -1
5354   },
5355   {
5356     Xacid_4,                            FALSE,  FALSE,
5357     EL_ACID,                            -1, -1
5358   },
5359   {
5360     Xacid_5,                            FALSE,  FALSE,
5361     EL_ACID,                            -1, -1
5362   },
5363   {
5364     Xacid_6,                            FALSE,  FALSE,
5365     EL_ACID,                            -1, -1
5366   },
5367   {
5368     Xacid_7,                            FALSE,  FALSE,
5369     EL_ACID,                            -1, -1
5370   },
5371   {
5372     Xacid_8,                            FALSE,  FALSE,
5373     EL_ACID,                            -1, -1
5374   },
5375   {
5376     Xball_1,                            TRUE,   FALSE,
5377     EL_EMC_MAGIC_BALL,                  -1, -1
5378   },
5379   {
5380     Xball_1B,                           FALSE,  FALSE,
5381     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5382   },
5383   {
5384     Xball_2,                            FALSE,  FALSE,
5385     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5386   },
5387   {
5388     Xball_2B,                           FALSE,  FALSE,
5389     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
5390   },
5391   {
5392     Yball_eat,                          FALSE,  FALSE,
5393     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
5394   },
5395   {
5396     Ykey_1_eat,                         FALSE,  FALSE,
5397     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
5398   },
5399   {
5400     Ykey_2_eat,                         FALSE,  FALSE,
5401     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
5402   },
5403   {
5404     Ykey_3_eat,                         FALSE,  FALSE,
5405     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
5406   },
5407   {
5408     Ykey_4_eat,                         FALSE,  FALSE,
5409     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
5410   },
5411   {
5412     Ykey_5_eat,                         FALSE,  FALSE,
5413     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
5414   },
5415   {
5416     Ykey_6_eat,                         FALSE,  FALSE,
5417     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
5418   },
5419   {
5420     Ykey_7_eat,                         FALSE,  FALSE,
5421     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
5422   },
5423   {
5424     Ykey_8_eat,                         FALSE,  FALSE,
5425     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
5426   },
5427   {
5428     Ylenses_eat,                        FALSE,  FALSE,
5429     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
5430   },
5431   {
5432     Ymagnify_eat,                       FALSE,  FALSE,
5433     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
5434   },
5435   {
5436     Ygrass_eat,                         FALSE,  FALSE,
5437     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
5438   },
5439   {
5440     Ydirt_eat,                          FALSE,  FALSE,
5441     EL_SAND,                            ACTION_SNAPPING, -1
5442   },
5443   {
5444     Xgrow_ns,                           TRUE,   FALSE,
5445     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
5446   },
5447   {
5448     Ygrow_ns_eat,                       FALSE,  FALSE,
5449     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
5450   },
5451   {
5452     Xgrow_ew,                           TRUE,   FALSE,
5453     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
5454   },
5455   {
5456     Ygrow_ew_eat,                       FALSE,  FALSE,
5457     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
5458   },
5459   {
5460     Xwonderwall,                        TRUE,   FALSE,
5461     EL_MAGIC_WALL,                      -1, -1
5462   },
5463   {
5464     XwonderwallB,                       FALSE,  FALSE,
5465     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
5466   },
5467   {
5468     Xamoeba_1,                          TRUE,   FALSE,
5469     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5470   },
5471   {
5472     Xamoeba_2,                          FALSE,  FALSE,
5473     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5474   },
5475   {
5476     Xamoeba_3,                          FALSE,  FALSE,
5477     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5478   },
5479   {
5480     Xamoeba_4,                          FALSE,  FALSE,
5481     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
5482   },
5483   {
5484     Xamoeba_5,                          TRUE,   FALSE,
5485     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5486   },
5487   {
5488     Xamoeba_6,                          FALSE,  FALSE,
5489     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5490   },
5491   {
5492     Xamoeba_7,                          FALSE,  FALSE,
5493     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5494   },
5495   {
5496     Xamoeba_8,                          FALSE,  FALSE,
5497     EL_AMOEBA_WET,                      ACTION_OTHER, -1
5498   },
5499   {
5500     Xdoor_1,                            TRUE,   FALSE,
5501     EL_EM_GATE_1,                       -1, -1
5502   },
5503   {
5504     Xdoor_2,                            TRUE,   FALSE,
5505     EL_EM_GATE_2,                       -1, -1
5506   },
5507   {
5508     Xdoor_3,                            TRUE,   FALSE,
5509     EL_EM_GATE_3,                       -1, -1
5510   },
5511   {
5512     Xdoor_4,                            TRUE,   FALSE,
5513     EL_EM_GATE_4,                       -1, -1
5514   },
5515   {
5516     Xdoor_5,                            TRUE,   FALSE,
5517     EL_EMC_GATE_5,                      -1, -1
5518   },
5519   {
5520     Xdoor_6,                            TRUE,   FALSE,
5521     EL_EMC_GATE_6,                      -1, -1
5522   },
5523   {
5524     Xdoor_7,                            TRUE,   FALSE,
5525     EL_EMC_GATE_7,                      -1, -1
5526   },
5527   {
5528     Xdoor_8,                            TRUE,   FALSE,
5529     EL_EMC_GATE_8,                      -1, -1
5530   },
5531   {
5532     Xkey_1,                             TRUE,   FALSE,
5533     EL_EM_KEY_1,                        -1, -1
5534   },
5535   {
5536     Xkey_2,                             TRUE,   FALSE,
5537     EL_EM_KEY_2,                        -1, -1
5538   },
5539   {
5540     Xkey_3,                             TRUE,   FALSE,
5541     EL_EM_KEY_3,                        -1, -1
5542   },
5543   {
5544     Xkey_4,                             TRUE,   FALSE,
5545     EL_EM_KEY_4,                        -1, -1
5546   },
5547   {
5548     Xkey_5,                             TRUE,   FALSE,
5549     EL_EMC_KEY_5,                       -1, -1
5550   },
5551   {
5552     Xkey_6,                             TRUE,   FALSE,
5553     EL_EMC_KEY_6,                       -1, -1
5554   },
5555   {
5556     Xkey_7,                             TRUE,   FALSE,
5557     EL_EMC_KEY_7,                       -1, -1
5558   },
5559   {
5560     Xkey_8,                             TRUE,   FALSE,
5561     EL_EMC_KEY_8,                       -1, -1
5562   },
5563   {
5564     Xwind_n,                            TRUE,   FALSE,
5565     EL_BALLOON_SWITCH_UP,               -1, -1
5566   },
5567   {
5568     Xwind_e,                            TRUE,   FALSE,
5569     EL_BALLOON_SWITCH_RIGHT,            -1, -1
5570   },
5571   {
5572     Xwind_s,                            TRUE,   FALSE,
5573     EL_BALLOON_SWITCH_DOWN,             -1, -1
5574   },
5575   {
5576     Xwind_w,                            TRUE,   FALSE,
5577     EL_BALLOON_SWITCH_LEFT,             -1, -1
5578   },
5579   {
5580     Xwind_nesw,                         TRUE,   FALSE,
5581     EL_BALLOON_SWITCH_ANY,              -1, -1
5582   },
5583   {
5584     Xwind_stop,                         TRUE,   FALSE,
5585     EL_BALLOON_SWITCH_NONE,             -1, -1
5586   },
5587   {
5588     Xexit,                              TRUE,   FALSE,
5589     EL_EM_EXIT_CLOSED,                  -1, -1
5590   },
5591   {
5592     Xexit_1,                            TRUE,   FALSE,
5593     EL_EM_EXIT_OPEN,                    -1, -1
5594   },
5595   {
5596     Xexit_2,                            FALSE,  FALSE,
5597     EL_EM_EXIT_OPEN,                    -1, -1
5598   },
5599   {
5600     Xexit_3,                            FALSE,  FALSE,
5601     EL_EM_EXIT_OPEN,                    -1, -1
5602   },
5603   {
5604     Xdynamite,                          TRUE,   FALSE,
5605     EL_EM_DYNAMITE,                     -1, -1
5606   },
5607   {
5608     Ydynamite_eat,                      FALSE,  FALSE,
5609     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
5610   },
5611   {
5612     Xdynamite_1,                        TRUE,   FALSE,
5613     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5614   },
5615   {
5616     Xdynamite_2,                        FALSE,  FALSE,
5617     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5618   },
5619   {
5620     Xdynamite_3,                        FALSE,  FALSE,
5621     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5622   },
5623   {
5624     Xdynamite_4,                        FALSE,  FALSE,
5625     EL_EM_DYNAMITE_ACTIVE,              -1, -1
5626   },
5627   {
5628     Xbumper,                            TRUE,   FALSE,
5629     EL_EMC_SPRING_BUMPER,               -1, -1
5630   },
5631   {
5632     XbumperB,                           FALSE,  FALSE,
5633     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
5634   },
5635   {
5636     Xwheel,                             TRUE,   FALSE,
5637     EL_ROBOT_WHEEL,                     -1, -1
5638   },
5639   {
5640     XwheelB,                            FALSE,  FALSE,
5641     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
5642   },
5643   {
5644     Xswitch,                            TRUE,   FALSE,
5645     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
5646   },
5647   {
5648     XswitchB,                           FALSE,  FALSE,
5649     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
5650   },
5651   {
5652     Xsand,                              TRUE,   FALSE,
5653     EL_QUICKSAND_EMPTY,                 -1, -1
5654   },
5655   {
5656     Xsand_stone,                        TRUE,   FALSE,
5657     EL_QUICKSAND_FULL,                  -1, -1
5658   },
5659   {
5660     Xsand_stonein_1,                    FALSE,  TRUE,
5661     EL_ROCK,                            ACTION_FILLING, -1
5662   },
5663   {
5664     Xsand_stonein_2,                    FALSE,  TRUE,
5665     EL_ROCK,                            ACTION_FILLING, -1
5666   },
5667   {
5668     Xsand_stonein_3,                    FALSE,  TRUE,
5669     EL_ROCK,                            ACTION_FILLING, -1
5670   },
5671   {
5672     Xsand_stonein_4,                    FALSE,  TRUE,
5673     EL_ROCK,                            ACTION_FILLING, -1
5674   },
5675   {
5676     Xsand_stonesand_1,                  FALSE,  FALSE,
5677     EL_QUICKSAND_EMPTYING,              -1, -1
5678   },
5679   {
5680     Xsand_stonesand_2,                  FALSE,  FALSE,
5681     EL_QUICKSAND_EMPTYING,              -1, -1
5682   },
5683   {
5684     Xsand_stonesand_3,                  FALSE,  FALSE,
5685     EL_QUICKSAND_EMPTYING,              -1, -1
5686   },
5687   {
5688     Xsand_stonesand_4,                  FALSE,  FALSE,
5689     EL_QUICKSAND_EMPTYING,              -1, -1
5690   },
5691   {
5692     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
5693     EL_QUICKSAND_EMPTYING,              -1, -1
5694   },
5695   {
5696     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
5697     EL_QUICKSAND_EMPTYING,              -1, -1
5698   },
5699   {
5700     Xsand_stoneout_1,                   FALSE,  FALSE,
5701     EL_ROCK,                            ACTION_EMPTYING, -1
5702   },
5703   {
5704     Xsand_stoneout_2,                   FALSE,  FALSE,
5705     EL_ROCK,                            ACTION_EMPTYING, -1
5706   },
5707   {
5708     Xsand_sandstone_1,                  FALSE,  FALSE,
5709     EL_QUICKSAND_FILLING,               -1, -1
5710   },
5711   {
5712     Xsand_sandstone_2,                  FALSE,  FALSE,
5713     EL_QUICKSAND_FILLING,               -1, -1
5714   },
5715   {
5716     Xsand_sandstone_3,                  FALSE,  FALSE,
5717     EL_QUICKSAND_FILLING,               -1, -1
5718   },
5719   {
5720     Xsand_sandstone_4,                  FALSE,  FALSE,
5721     EL_QUICKSAND_FILLING,               -1, -1
5722   },
5723   {
5724     Xplant,                             TRUE,   FALSE,
5725     EL_EMC_PLANT,                       -1, -1
5726   },
5727   {
5728     Yplant,                             FALSE,  FALSE,
5729     EL_EMC_PLANT,                       -1, -1
5730   },
5731   {
5732     Xlenses,                            TRUE,   FALSE,
5733     EL_EMC_LENSES,                      -1, -1
5734   },
5735   {
5736     Xmagnify,                           TRUE,   FALSE,
5737     EL_EMC_MAGNIFIER,                   -1, -1
5738   },
5739   {
5740     Xdripper,                           TRUE,   FALSE,
5741     EL_EMC_DRIPPER,                     -1, -1
5742   },
5743   {
5744     XdripperB,                          FALSE,  FALSE,
5745     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
5746   },
5747   {
5748     Xfake_blank,                        TRUE,   FALSE,
5749     EL_INVISIBLE_WALL,                  -1, -1
5750   },
5751   {
5752     Xfake_blankB,                       FALSE,  FALSE,
5753     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
5754   },
5755   {
5756     Xfake_grass,                        TRUE,   FALSE,
5757     EL_EMC_FAKE_GRASS,                  -1, -1
5758   },
5759   {
5760     Xfake_grassB,                       FALSE,  FALSE,
5761     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
5762   },
5763   {
5764     Xfake_door_1,                       TRUE,   FALSE,
5765     EL_EM_GATE_1_GRAY,                  -1, -1
5766   },
5767   {
5768     Xfake_door_2,                       TRUE,   FALSE,
5769     EL_EM_GATE_2_GRAY,                  -1, -1
5770   },
5771   {
5772     Xfake_door_3,                       TRUE,   FALSE,
5773     EL_EM_GATE_3_GRAY,                  -1, -1
5774   },
5775   {
5776     Xfake_door_4,                       TRUE,   FALSE,
5777     EL_EM_GATE_4_GRAY,                  -1, -1
5778   },
5779   {
5780     Xfake_door_5,                       TRUE,   FALSE,
5781     EL_EMC_GATE_5_GRAY,                 -1, -1
5782   },
5783   {
5784     Xfake_door_6,                       TRUE,   FALSE,
5785     EL_EMC_GATE_6_GRAY,                 -1, -1
5786   },
5787   {
5788     Xfake_door_7,                       TRUE,   FALSE,
5789     EL_EMC_GATE_7_GRAY,                 -1, -1
5790   },
5791   {
5792     Xfake_door_8,                       TRUE,   FALSE,
5793     EL_EMC_GATE_8_GRAY,                 -1, -1
5794   },
5795   {
5796     Xfake_acid_1,                       TRUE,   FALSE,
5797     EL_EMC_FAKE_ACID,                   -1, -1
5798   },
5799   {
5800     Xfake_acid_2,                       FALSE,  FALSE,
5801     EL_EMC_FAKE_ACID,                   -1, -1
5802   },
5803   {
5804     Xfake_acid_3,                       FALSE,  FALSE,
5805     EL_EMC_FAKE_ACID,                   -1, -1
5806   },
5807   {
5808     Xfake_acid_4,                       FALSE,  FALSE,
5809     EL_EMC_FAKE_ACID,                   -1, -1
5810   },
5811   {
5812     Xfake_acid_5,                       FALSE,  FALSE,
5813     EL_EMC_FAKE_ACID,                   -1, -1
5814   },
5815   {
5816     Xfake_acid_6,                       FALSE,  FALSE,
5817     EL_EMC_FAKE_ACID,                   -1, -1
5818   },
5819   {
5820     Xfake_acid_7,                       FALSE,  FALSE,
5821     EL_EMC_FAKE_ACID,                   -1, -1
5822   },
5823   {
5824     Xfake_acid_8,                       FALSE,  FALSE,
5825     EL_EMC_FAKE_ACID,                   -1, -1
5826   },
5827   {
5828     Xsteel_1,                           TRUE,   FALSE,
5829     EL_STEELWALL,                       -1, -1
5830   },
5831   {
5832     Xsteel_2,                           TRUE,   FALSE,
5833     EL_EMC_STEELWALL_2,                 -1, -1
5834   },
5835   {
5836     Xsteel_3,                           TRUE,   FALSE,
5837     EL_EMC_STEELWALL_3,                 -1, -1
5838   },
5839   {
5840     Xsteel_4,                           TRUE,   FALSE,
5841     EL_EMC_STEELWALL_4,                 -1, -1
5842   },
5843   {
5844     Xwall_1,                            TRUE,   FALSE,
5845     EL_WALL,                            -1, -1
5846   },
5847   {
5848     Xwall_2,                            TRUE,   FALSE,
5849     EL_EMC_WALL_14,                     -1, -1
5850   },
5851   {
5852     Xwall_3,                            TRUE,   FALSE,
5853     EL_EMC_WALL_15,                     -1, -1
5854   },
5855   {
5856     Xwall_4,                            TRUE,   FALSE,
5857     EL_EMC_WALL_16,                     -1, -1
5858   },
5859   {
5860     Xround_wall_1,                      TRUE,   FALSE,
5861     EL_WALL_SLIPPERY,                   -1, -1
5862   },
5863   {
5864     Xround_wall_2,                      TRUE,   FALSE,
5865     EL_EMC_WALL_SLIPPERY_2,             -1, -1
5866   },
5867   {
5868     Xround_wall_3,                      TRUE,   FALSE,
5869     EL_EMC_WALL_SLIPPERY_3,             -1, -1
5870   },
5871   {
5872     Xround_wall_4,                      TRUE,   FALSE,
5873     EL_EMC_WALL_SLIPPERY_4,             -1, -1
5874   },
5875   {
5876     Xdecor_1,                           TRUE,   FALSE,
5877     EL_EMC_WALL_8,                      -1, -1
5878   },
5879   {
5880     Xdecor_2,                           TRUE,   FALSE,
5881     EL_EMC_WALL_6,                      -1, -1
5882   },
5883   {
5884     Xdecor_3,                           TRUE,   FALSE,
5885     EL_EMC_WALL_4,                      -1, -1
5886   },
5887   {
5888     Xdecor_4,                           TRUE,   FALSE,
5889     EL_EMC_WALL_7,                      -1, -1
5890   },
5891   {
5892     Xdecor_5,                           TRUE,   FALSE,
5893     EL_EMC_WALL_5,                      -1, -1
5894   },
5895   {
5896     Xdecor_6,                           TRUE,   FALSE,
5897     EL_EMC_WALL_9,                      -1, -1
5898   },
5899   {
5900     Xdecor_7,                           TRUE,   FALSE,
5901     EL_EMC_WALL_10,                     -1, -1
5902   },
5903   {
5904     Xdecor_8,                           TRUE,   FALSE,
5905     EL_EMC_WALL_1,                      -1, -1
5906   },
5907   {
5908     Xdecor_9,                           TRUE,   FALSE,
5909     EL_EMC_WALL_2,                      -1, -1
5910   },
5911   {
5912     Xdecor_10,                          TRUE,   FALSE,
5913     EL_EMC_WALL_3,                      -1, -1
5914   },
5915   {
5916     Xdecor_11,                          TRUE,   FALSE,
5917     EL_EMC_WALL_11,                     -1, -1
5918   },
5919   {
5920     Xdecor_12,                          TRUE,   FALSE,
5921     EL_EMC_WALL_12,                     -1, -1
5922   },
5923   {
5924     Xalpha_0,                           TRUE,   FALSE,
5925     EL_CHAR('0'),                       -1, -1
5926   },
5927   {
5928     Xalpha_1,                           TRUE,   FALSE,
5929     EL_CHAR('1'),                       -1, -1
5930   },
5931   {
5932     Xalpha_2,                           TRUE,   FALSE,
5933     EL_CHAR('2'),                       -1, -1
5934   },
5935   {
5936     Xalpha_3,                           TRUE,   FALSE,
5937     EL_CHAR('3'),                       -1, -1
5938   },
5939   {
5940     Xalpha_4,                           TRUE,   FALSE,
5941     EL_CHAR('4'),                       -1, -1
5942   },
5943   {
5944     Xalpha_5,                           TRUE,   FALSE,
5945     EL_CHAR('5'),                       -1, -1
5946   },
5947   {
5948     Xalpha_6,                           TRUE,   FALSE,
5949     EL_CHAR('6'),                       -1, -1
5950   },
5951   {
5952     Xalpha_7,                           TRUE,   FALSE,
5953     EL_CHAR('7'),                       -1, -1
5954   },
5955   {
5956     Xalpha_8,                           TRUE,   FALSE,
5957     EL_CHAR('8'),                       -1, -1
5958   },
5959   {
5960     Xalpha_9,                           TRUE,   FALSE,
5961     EL_CHAR('9'),                       -1, -1
5962   },
5963   {
5964     Xalpha_excla,                       TRUE,   FALSE,
5965     EL_CHAR('!'),                       -1, -1
5966   },
5967   {
5968     Xalpha_quote,                       TRUE,   FALSE,
5969     EL_CHAR('"'),                       -1, -1
5970   },
5971   {
5972     Xalpha_comma,                       TRUE,   FALSE,
5973     EL_CHAR(','),                       -1, -1
5974   },
5975   {
5976     Xalpha_minus,                       TRUE,   FALSE,
5977     EL_CHAR('-'),                       -1, -1
5978   },
5979   {
5980     Xalpha_perio,                       TRUE,   FALSE,
5981     EL_CHAR('.'),                       -1, -1
5982   },
5983   {
5984     Xalpha_colon,                       TRUE,   FALSE,
5985     EL_CHAR(':'),                       -1, -1
5986   },
5987   {
5988     Xalpha_quest,                       TRUE,   FALSE,
5989     EL_CHAR('?'),                       -1, -1
5990   },
5991   {
5992     Xalpha_a,                           TRUE,   FALSE,
5993     EL_CHAR('A'),                       -1, -1
5994   },
5995   {
5996     Xalpha_b,                           TRUE,   FALSE,
5997     EL_CHAR('B'),                       -1, -1
5998   },
5999   {
6000     Xalpha_c,                           TRUE,   FALSE,
6001     EL_CHAR('C'),                       -1, -1
6002   },
6003   {
6004     Xalpha_d,                           TRUE,   FALSE,
6005     EL_CHAR('D'),                       -1, -1
6006   },
6007   {
6008     Xalpha_e,                           TRUE,   FALSE,
6009     EL_CHAR('E'),                       -1, -1
6010   },
6011   {
6012     Xalpha_f,                           TRUE,   FALSE,
6013     EL_CHAR('F'),                       -1, -1
6014   },
6015   {
6016     Xalpha_g,                           TRUE,   FALSE,
6017     EL_CHAR('G'),                       -1, -1
6018   },
6019   {
6020     Xalpha_h,                           TRUE,   FALSE,
6021     EL_CHAR('H'),                       -1, -1
6022   },
6023   {
6024     Xalpha_i,                           TRUE,   FALSE,
6025     EL_CHAR('I'),                       -1, -1
6026   },
6027   {
6028     Xalpha_j,                           TRUE,   FALSE,
6029     EL_CHAR('J'),                       -1, -1
6030   },
6031   {
6032     Xalpha_k,                           TRUE,   FALSE,
6033     EL_CHAR('K'),                       -1, -1
6034   },
6035   {
6036     Xalpha_l,                           TRUE,   FALSE,
6037     EL_CHAR('L'),                       -1, -1
6038   },
6039   {
6040     Xalpha_m,                           TRUE,   FALSE,
6041     EL_CHAR('M'),                       -1, -1
6042   },
6043   {
6044     Xalpha_n,                           TRUE,   FALSE,
6045     EL_CHAR('N'),                       -1, -1
6046   },
6047   {
6048     Xalpha_o,                           TRUE,   FALSE,
6049     EL_CHAR('O'),                       -1, -1
6050   },
6051   {
6052     Xalpha_p,                           TRUE,   FALSE,
6053     EL_CHAR('P'),                       -1, -1
6054   },
6055   {
6056     Xalpha_q,                           TRUE,   FALSE,
6057     EL_CHAR('Q'),                       -1, -1
6058   },
6059   {
6060     Xalpha_r,                           TRUE,   FALSE,
6061     EL_CHAR('R'),                       -1, -1
6062   },
6063   {
6064     Xalpha_s,                           TRUE,   FALSE,
6065     EL_CHAR('S'),                       -1, -1
6066   },
6067   {
6068     Xalpha_t,                           TRUE,   FALSE,
6069     EL_CHAR('T'),                       -1, -1
6070   },
6071   {
6072     Xalpha_u,                           TRUE,   FALSE,
6073     EL_CHAR('U'),                       -1, -1
6074   },
6075   {
6076     Xalpha_v,                           TRUE,   FALSE,
6077     EL_CHAR('V'),                       -1, -1
6078   },
6079   {
6080     Xalpha_w,                           TRUE,   FALSE,
6081     EL_CHAR('W'),                       -1, -1
6082   },
6083   {
6084     Xalpha_x,                           TRUE,   FALSE,
6085     EL_CHAR('X'),                       -1, -1
6086   },
6087   {
6088     Xalpha_y,                           TRUE,   FALSE,
6089     EL_CHAR('Y'),                       -1, -1
6090   },
6091   {
6092     Xalpha_z,                           TRUE,   FALSE,
6093     EL_CHAR('Z'),                       -1, -1
6094   },
6095   {
6096     Xalpha_arrow_e,                     TRUE,   FALSE,
6097     EL_CHAR('>'),                       -1, -1
6098   },
6099   {
6100     Xalpha_arrow_w,                     TRUE,   FALSE,
6101     EL_CHAR('<'),                       -1, -1
6102   },
6103   {
6104     Xalpha_copyr,                       TRUE,   FALSE,
6105     EL_CHAR(CHAR_BYTE_COPYRIGHT),       -1, -1
6106   },
6107
6108   {
6109     Xboom_bug,                          FALSE,  FALSE,
6110     EL_BUG,                             ACTION_EXPLODING, -1
6111   },
6112   {
6113     Xboom_bomb,                         FALSE,  FALSE,
6114     EL_BOMB,                            ACTION_EXPLODING, -1
6115   },
6116   {
6117     Xboom_android,                      FALSE,  FALSE,
6118     EL_EMC_ANDROID,                     ACTION_OTHER, -1
6119   },
6120   {
6121     Xboom_1,                            FALSE,  FALSE,
6122     EL_DEFAULT,                         ACTION_EXPLODING, -1
6123   },
6124   {
6125     Xboom_2,                            FALSE,  FALSE,
6126     EL_DEFAULT,                         ACTION_EXPLODING, -1
6127   },
6128   {
6129     Znormal,                            FALSE,  FALSE,
6130     EL_EMPTY,                           -1, -1
6131   },
6132   {
6133     Zdynamite,                          FALSE,  FALSE,
6134     EL_EMPTY,                           -1, -1
6135   },
6136   {
6137     Zplayer,                            FALSE,  FALSE,
6138     EL_EMPTY,                           -1, -1
6139   },
6140   {
6141     ZBORDER,                            FALSE,  FALSE,
6142     EL_EMPTY,                           -1, -1
6143   },
6144
6145   {
6146     -1,                                 FALSE,  FALSE,
6147     -1,                                 -1, -1
6148   }
6149 };
6150
6151 static struct Mapping_EM_to_RND_player
6152 {
6153   int action_em;
6154   int player_nr;
6155
6156   int element_rnd;
6157   int action;
6158   int direction;
6159 }
6160 em_player_mapping_list[] =
6161 {
6162   {
6163     SPR_walk + 0,                       0,
6164     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
6165   },
6166   {
6167     SPR_walk + 1,                       0,
6168     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
6169   },
6170   {
6171     SPR_walk + 2,                       0,
6172     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
6173   },
6174   {
6175     SPR_walk + 3,                       0,
6176     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
6177   },
6178   {
6179     SPR_push + 0,                       0,
6180     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
6181   },
6182   {
6183     SPR_push + 1,                       0,
6184     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
6185   },
6186   {
6187     SPR_push + 2,                       0,
6188     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
6189   },
6190   {
6191     SPR_push + 3,                       0,
6192     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
6193   },
6194   {
6195     SPR_spray + 0,                      0,
6196     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
6197   },
6198   {
6199     SPR_spray + 1,                      0,
6200     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6201   },
6202   {
6203     SPR_spray + 2,                      0,
6204     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
6205   },
6206   {
6207     SPR_spray + 3,                      0,
6208     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
6209   },
6210   {
6211     SPR_walk + 0,                       1,
6212     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
6213   },
6214   {
6215     SPR_walk + 1,                       1,
6216     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
6217   },
6218   {
6219     SPR_walk + 2,                       1,
6220     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
6221   },
6222   {
6223     SPR_walk + 3,                       1,
6224     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
6225   },
6226   {
6227     SPR_push + 0,                       1,
6228     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
6229   },
6230   {
6231     SPR_push + 1,                       1,
6232     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
6233   },
6234   {
6235     SPR_push + 2,                       1,
6236     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
6237   },
6238   {
6239     SPR_push + 3,                       1,
6240     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
6241   },
6242   {
6243     SPR_spray + 0,                      1,
6244     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
6245   },
6246   {
6247     SPR_spray + 1,                      1,
6248     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6249   },
6250   {
6251     SPR_spray + 2,                      1,
6252     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
6253   },
6254   {
6255     SPR_spray + 3,                      1,
6256     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
6257   },
6258   {
6259     SPR_still,                          0,
6260     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
6261   },
6262   {
6263     SPR_still,                          1,
6264     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
6265   },
6266   {
6267     SPR_walk + 0,                       2,
6268     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
6269   },
6270   {
6271     SPR_walk + 1,                       2,
6272     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
6273   },
6274   {
6275     SPR_walk + 2,                       2,
6276     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
6277   },
6278   {
6279     SPR_walk + 3,                       2,
6280     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
6281   },
6282   {
6283     SPR_push + 0,                       2,
6284     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
6285   },
6286   {
6287     SPR_push + 1,                       2,
6288     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
6289   },
6290   {
6291     SPR_push + 2,                       2,
6292     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
6293   },
6294   {
6295     SPR_push + 3,                       2,
6296     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
6297   },
6298   {
6299     SPR_spray + 0,                      2,
6300     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
6301   },
6302   {
6303     SPR_spray + 1,                      2,
6304     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6305   },
6306   {
6307     SPR_spray + 2,                      2,
6308     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
6309   },
6310   {
6311     SPR_spray + 3,                      2,
6312     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
6313   },
6314   {
6315     SPR_walk + 0,                       3,
6316     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
6317   },
6318   {
6319     SPR_walk + 1,                       3,
6320     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
6321   },
6322   {
6323     SPR_walk + 2,                       3,
6324     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
6325   },
6326   {
6327     SPR_walk + 3,                       3,
6328     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
6329   },
6330   {
6331     SPR_push + 0,                       3,
6332     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
6333   },
6334   {
6335     SPR_push + 1,                       3,
6336     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
6337   },
6338   {
6339     SPR_push + 2,                       3,
6340     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
6341   },
6342   {
6343     SPR_push + 3,                       3,
6344     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
6345   },
6346   {
6347     SPR_spray + 0,                      3,
6348     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
6349   },
6350   {
6351     SPR_spray + 1,                      3,
6352     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
6353   },
6354   {
6355     SPR_spray + 2,                      3,
6356     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
6357   },
6358   {
6359     SPR_spray + 3,                      3,
6360     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
6361   },
6362   {
6363     SPR_still,                          2,
6364     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
6365   },
6366   {
6367     SPR_still,                          3,
6368     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
6369   },
6370
6371   {
6372     -1,                                 -1,
6373     -1,                                 -1, -1
6374   }
6375 };
6376
6377 int map_element_RND_to_EM(int element_rnd)
6378 {
6379   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6380   static boolean mapping_initialized = FALSE;
6381
6382   if (!mapping_initialized)
6383   {
6384     int i;
6385
6386     /* return "Xalpha_quest" for all undefined elements in mapping array */
6387     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6388       mapping_RND_to_EM[i] = Xalpha_quest;
6389
6390     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6391       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6392         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6393           em_object_mapping_list[i].element_em;
6394
6395     mapping_initialized = TRUE;
6396   }
6397
6398   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6399     return mapping_RND_to_EM[element_rnd];
6400
6401   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6402
6403   return EL_UNKNOWN;
6404 }
6405
6406 int map_element_EM_to_RND(int element_em)
6407 {
6408   static unsigned short mapping_EM_to_RND[TILE_MAX];
6409   static boolean mapping_initialized = FALSE;
6410
6411   if (!mapping_initialized)
6412   {
6413     int i;
6414
6415     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6416     for (i = 0; i < TILE_MAX; i++)
6417       mapping_EM_to_RND[i] = EL_UNKNOWN;
6418
6419     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6420       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6421         em_object_mapping_list[i].element_rnd;
6422
6423     mapping_initialized = TRUE;
6424   }
6425
6426   if (element_em >= 0 && element_em < TILE_MAX)
6427     return mapping_EM_to_RND[element_em];
6428
6429   Error(ERR_WARN, "invalid EM level element %d", element_em);
6430
6431   return EL_UNKNOWN;
6432 }
6433
6434 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6435 {
6436   struct LevelInfo_EM *level_em = level->native_em_level;
6437   struct LEVEL *lev = level_em->lev;
6438   int i, j;
6439
6440   for (i = 0; i < TILE_MAX; i++)
6441     lev->android_array[i] = Xblank;
6442
6443   for (i = 0; i < level->num_android_clone_elements; i++)
6444   {
6445     int element_rnd = level->android_clone_element[i];
6446     int element_em = map_element_RND_to_EM(element_rnd);
6447
6448     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6449       if (em_object_mapping_list[j].element_rnd == element_rnd)
6450         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6451   }
6452 }
6453
6454 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6455 {
6456   struct LevelInfo_EM *level_em = level->native_em_level;
6457   struct LEVEL *lev = level_em->lev;
6458   int i, j;
6459
6460   level->num_android_clone_elements = 0;
6461
6462   for (i = 0; i < TILE_MAX; i++)
6463   {
6464     int element_em = lev->android_array[i];
6465     int element_rnd;
6466     boolean element_found = FALSE;
6467
6468     if (element_em == Xblank)
6469       continue;
6470
6471     element_rnd = map_element_EM_to_RND(element_em);
6472
6473     for (j = 0; j < level->num_android_clone_elements; j++)
6474       if (level->android_clone_element[j] == element_rnd)
6475         element_found = TRUE;
6476
6477     if (!element_found)
6478     {
6479       level->android_clone_element[level->num_android_clone_elements++] =
6480         element_rnd;
6481
6482       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6483         break;
6484     }
6485   }
6486
6487   if (level->num_android_clone_elements == 0)
6488   {
6489     level->num_android_clone_elements = 1;
6490     level->android_clone_element[0] = EL_EMPTY;
6491   }
6492 }
6493
6494 int map_direction_RND_to_EM(int direction)
6495 {
6496   return (direction == MV_UP    ? 0 :
6497           direction == MV_RIGHT ? 1 :
6498           direction == MV_DOWN  ? 2 :
6499           direction == MV_LEFT  ? 3 :
6500           -1);
6501 }
6502
6503 int map_direction_EM_to_RND(int direction)
6504 {
6505   return (direction == 0 ? MV_UP    :
6506           direction == 1 ? MV_RIGHT :
6507           direction == 2 ? MV_DOWN  :
6508           direction == 3 ? MV_LEFT  :
6509           MV_NONE);
6510 }
6511
6512 int map_element_RND_to_SP(int element_rnd)
6513 {
6514   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
6515
6516   if (element_rnd >= EL_SP_START &&
6517       element_rnd <= EL_SP_END)
6518     element_sp = element_rnd - EL_SP_START;
6519   else if (element_rnd == EL_EMPTY_SPACE)
6520     element_sp = 0x00;
6521   else if (element_rnd == EL_INVISIBLE_WALL)
6522     element_sp = 0x28;
6523
6524   return element_sp;
6525 }
6526
6527 int map_element_SP_to_RND(int element_sp)
6528 {
6529   int element_rnd = EL_UNKNOWN;
6530
6531   if (element_sp >= 0x00 &&
6532       element_sp <= 0x27)
6533     element_rnd = EL_SP_START + element_sp;
6534   else if (element_sp == 0x28)
6535     element_rnd = EL_INVISIBLE_WALL;
6536
6537   return element_rnd;
6538 }
6539
6540 int map_action_SP_to_RND(int action_sp)
6541 {
6542   switch (action_sp)
6543   {
6544     case actActive:             return ACTION_ACTIVE;
6545     case actImpact:             return ACTION_IMPACT;
6546     case actExploding:          return ACTION_EXPLODING;
6547     case actDigging:            return ACTION_DIGGING;
6548     case actSnapping:           return ACTION_SNAPPING;
6549     case actCollecting:         return ACTION_COLLECTING;
6550     case actPassing:            return ACTION_PASSING;
6551     case actPushing:            return ACTION_PUSHING;
6552     case actDropping:           return ACTION_DROPPING;
6553
6554     default:                    return ACTION_DEFAULT;
6555   }
6556 }
6557
6558 int get_next_element(int element)
6559 {
6560   switch (element)
6561   {
6562     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
6563     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
6564     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
6565     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
6566     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
6567     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
6568     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
6569     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
6570     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
6571     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
6572     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
6573
6574     default:                            return element;
6575   }
6576 }
6577
6578 int el_act_dir2img(int element, int action, int direction)
6579 {
6580   element = GFX_ELEMENT(element);
6581   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6582
6583   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6584   return element_info[element].direction_graphic[action][direction];
6585 }
6586
6587 static int el_act_dir2crm(int element, int action, int direction)
6588 {
6589   element = GFX_ELEMENT(element);
6590   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6591
6592   /* direction_graphic[][] == graphic[] for undefined direction graphics */
6593   return element_info[element].direction_crumbled[action][direction];
6594 }
6595
6596 int el_act2img(int element, int action)
6597 {
6598   element = GFX_ELEMENT(element);
6599
6600   return element_info[element].graphic[action];
6601 }
6602
6603 int el_act2crm(int element, int action)
6604 {
6605   element = GFX_ELEMENT(element);
6606
6607   return element_info[element].crumbled[action];
6608 }
6609
6610 int el_dir2img(int element, int direction)
6611 {
6612   element = GFX_ELEMENT(element);
6613
6614   return el_act_dir2img(element, ACTION_DEFAULT, direction);
6615 }
6616
6617 int el2baseimg(int element)
6618 {
6619   return element_info[element].graphic[ACTION_DEFAULT];
6620 }
6621
6622 int el2img(int element)
6623 {
6624   element = GFX_ELEMENT(element);
6625
6626   return element_info[element].graphic[ACTION_DEFAULT];
6627 }
6628
6629 int el2edimg(int element)
6630 {
6631   element = GFX_ELEMENT(element);
6632
6633   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6634 }
6635
6636 int el2preimg(int element)
6637 {
6638   element = GFX_ELEMENT(element);
6639
6640   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6641 }
6642
6643 int el2panelimg(int element)
6644 {
6645   element = GFX_ELEMENT(element);
6646
6647   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6648 }
6649
6650 int font2baseimg(int font_nr)
6651 {
6652   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6653 }
6654
6655 int getBeltNrFromBeltElement(int element)
6656 {
6657   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6658           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6659           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6660 }
6661
6662 int getBeltNrFromBeltActiveElement(int element)
6663 {
6664   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6665           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6666           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6667 }
6668
6669 int getBeltNrFromBeltSwitchElement(int element)
6670 {
6671   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6672           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6673           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6674 }
6675
6676 int getBeltDirNrFromBeltElement(int element)
6677 {
6678   static int belt_base_element[4] =
6679   {
6680     EL_CONVEYOR_BELT_1_LEFT,
6681     EL_CONVEYOR_BELT_2_LEFT,
6682     EL_CONVEYOR_BELT_3_LEFT,
6683     EL_CONVEYOR_BELT_4_LEFT
6684   };
6685
6686   int belt_nr = getBeltNrFromBeltElement(element);
6687   int belt_dir_nr = element - belt_base_element[belt_nr];
6688
6689   return (belt_dir_nr % 3);
6690 }
6691
6692 int getBeltDirNrFromBeltSwitchElement(int element)
6693 {
6694   static int belt_base_element[4] =
6695   {
6696     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6697     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6698     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6699     EL_CONVEYOR_BELT_4_SWITCH_LEFT
6700   };
6701
6702   int belt_nr = getBeltNrFromBeltSwitchElement(element);
6703   int belt_dir_nr = element - belt_base_element[belt_nr];
6704
6705   return (belt_dir_nr % 3);
6706 }
6707
6708 int getBeltDirFromBeltElement(int element)
6709 {
6710   static int belt_move_dir[3] =
6711   {
6712     MV_LEFT,
6713     MV_NONE,
6714     MV_RIGHT
6715   };
6716
6717   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6718
6719   return belt_move_dir[belt_dir_nr];
6720 }
6721
6722 int getBeltDirFromBeltSwitchElement(int element)
6723 {
6724   static int belt_move_dir[3] =
6725   {
6726     MV_LEFT,
6727     MV_NONE,
6728     MV_RIGHT
6729   };
6730
6731   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6732
6733   return belt_move_dir[belt_dir_nr];
6734 }
6735
6736 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6737 {
6738   static int belt_base_element[4] =
6739   {
6740     EL_CONVEYOR_BELT_1_LEFT,
6741     EL_CONVEYOR_BELT_2_LEFT,
6742     EL_CONVEYOR_BELT_3_LEFT,
6743     EL_CONVEYOR_BELT_4_LEFT
6744   };
6745
6746   return belt_base_element[belt_nr] + belt_dir_nr;
6747 }
6748
6749 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6750 {
6751   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6752
6753   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6754 }
6755
6756 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6757 {
6758   static int belt_base_element[4] =
6759   {
6760     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6761     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6762     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6763     EL_CONVEYOR_BELT_4_SWITCH_LEFT
6764   };
6765
6766   return belt_base_element[belt_nr] + belt_dir_nr;
6767 }
6768
6769 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6770 {
6771   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6772
6773   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6774 }
6775
6776 boolean getTeamMode_EM()
6777 {
6778   return game.team_mode;
6779 }
6780
6781 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6782 {
6783   int game_frame_delay_value;
6784
6785   game_frame_delay_value =
6786     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6787      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6788      GameFrameDelay);
6789
6790   if (tape.playing && tape.warp_forward && !tape.pausing)
6791     game_frame_delay_value = 0;
6792
6793   return game_frame_delay_value;
6794 }
6795
6796 unsigned int InitRND(int seed)
6797 {
6798   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6799     return InitEngineRandom_EM(seed);
6800   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6801     return InitEngineRandom_SP(seed);
6802   else
6803     return InitEngineRandom_RND(seed);
6804 }
6805
6806 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6807 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6808
6809 inline static int get_effective_element_EM(int tile, int frame_em)
6810 {
6811   int element             = object_mapping[tile].element_rnd;
6812   int action              = object_mapping[tile].action;
6813   boolean is_backside     = object_mapping[tile].is_backside;
6814   boolean action_removing = (action == ACTION_DIGGING ||
6815                              action == ACTION_SNAPPING ||
6816                              action == ACTION_COLLECTING);
6817
6818   if (frame_em < 7)
6819   {
6820     switch (tile)
6821     {
6822       case Yacid_splash_eB:
6823       case Yacid_splash_wB:
6824         return (frame_em > 5 ? EL_EMPTY : element);
6825
6826       default:
6827         return element;
6828     }
6829   }
6830   else  /* frame_em == 7 */
6831   {
6832     switch (tile)
6833     {
6834       case Yacid_splash_eB:
6835       case Yacid_splash_wB:
6836         return EL_EMPTY;
6837
6838       case Yemerald_stone:
6839         return EL_EMERALD;
6840
6841       case Ydiamond_stone:
6842         return EL_ROCK;
6843
6844       case Xdrip_stretch:
6845       case Xdrip_stretchB:
6846       case Ydrip_s1:
6847       case Ydrip_s1B:
6848       case Xball_1B:
6849       case Xball_2:
6850       case Xball_2B:
6851       case Yball_eat:
6852       case Ykey_1_eat:
6853       case Ykey_2_eat:
6854       case Ykey_3_eat:
6855       case Ykey_4_eat:
6856       case Ykey_5_eat:
6857       case Ykey_6_eat:
6858       case Ykey_7_eat:
6859       case Ykey_8_eat:
6860       case Ylenses_eat:
6861       case Ymagnify_eat:
6862       case Ygrass_eat:
6863       case Ydirt_eat:
6864       case Xsand_stonein_1:
6865       case Xsand_stonein_2:
6866       case Xsand_stonein_3:
6867       case Xsand_stonein_4:
6868         return element;
6869
6870       default:
6871         return (is_backside || action_removing ? EL_EMPTY : element);
6872     }
6873   }
6874 }
6875
6876 inline static boolean check_linear_animation_EM(int tile)
6877 {
6878   switch (tile)
6879   {
6880     case Xsand_stonesand_1:
6881     case Xsand_stonesand_quickout_1:
6882     case Xsand_sandstone_1:
6883     case Xsand_stonein_1:
6884     case Xsand_stoneout_1:
6885     case Xboom_1:
6886     case Xdynamite_1:
6887     case Ybug_w_n:
6888     case Ybug_n_e:
6889     case Ybug_e_s:
6890     case Ybug_s_w:
6891     case Ybug_e_n:
6892     case Ybug_s_e:
6893     case Ybug_w_s:
6894     case Ybug_n_w:
6895     case Ytank_w_n:
6896     case Ytank_n_e:
6897     case Ytank_e_s:
6898     case Ytank_s_w:
6899     case Ytank_e_n:
6900     case Ytank_s_e:
6901     case Ytank_w_s:
6902     case Ytank_n_w:
6903     case Yacid_splash_eB:
6904     case Yacid_splash_wB:
6905     case Yemerald_stone:
6906       return TRUE;
6907   }
6908
6909   return FALSE;
6910 }
6911
6912 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6913                                             boolean has_crumbled_graphics,
6914                                             int crumbled, int sync_frame)
6915 {
6916   /* if element can be crumbled, but certain action graphics are just empty
6917      space (like instantly snapping sand to empty space in 1 frame), do not
6918      treat these empty space graphics as crumbled graphics in EMC engine */
6919   if (crumbled == IMG_EMPTY_SPACE)
6920     has_crumbled_graphics = FALSE;
6921
6922   if (has_crumbled_graphics)
6923   {
6924     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6925     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6926                                            g_crumbled->anim_delay,
6927                                            g_crumbled->anim_mode,
6928                                            g_crumbled->anim_start_frame,
6929                                            sync_frame);
6930
6931     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6932                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6933
6934     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6935
6936     g_em->has_crumbled_graphics = TRUE;
6937   }
6938   else
6939   {
6940     g_em->crumbled_bitmap = NULL;
6941     g_em->crumbled_src_x = 0;
6942     g_em->crumbled_src_y = 0;
6943     g_em->crumbled_border_size = 0;
6944
6945     g_em->has_crumbled_graphics = FALSE;
6946   }
6947 }
6948
6949 void ResetGfxAnimation_EM(int x, int y, int tile)
6950 {
6951   GfxFrame[x][y] = 0;
6952 }
6953
6954 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6955                         int tile, int frame_em, int x, int y)
6956 {
6957   int action = object_mapping[tile].action;
6958   int direction = object_mapping[tile].direction;
6959   int effective_element = get_effective_element_EM(tile, frame_em);
6960   int graphic = (direction == MV_NONE ?
6961                  el_act2img(effective_element, action) :
6962                  el_act_dir2img(effective_element, action, direction));
6963   struct GraphicInfo *g = &graphic_info[graphic];
6964   int sync_frame;
6965   boolean action_removing = (action == ACTION_DIGGING ||
6966                              action == ACTION_SNAPPING ||
6967                              action == ACTION_COLLECTING);
6968   boolean action_moving   = (action == ACTION_FALLING ||
6969                              action == ACTION_MOVING ||
6970                              action == ACTION_PUSHING ||
6971                              action == ACTION_EATING ||
6972                              action == ACTION_FILLING ||
6973                              action == ACTION_EMPTYING);
6974   boolean action_falling  = (action == ACTION_FALLING ||
6975                              action == ACTION_FILLING ||
6976                              action == ACTION_EMPTYING);
6977
6978   /* special case: graphic uses "2nd movement tile" and has defined
6979      7 frames for movement animation (or less) => use default graphic
6980      for last (8th) frame which ends the movement animation */
6981   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6982   {
6983     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
6984     graphic = (direction == MV_NONE ?
6985                el_act2img(effective_element, action) :
6986                el_act_dir2img(effective_element, action, direction));
6987
6988     g = &graphic_info[graphic];
6989   }
6990
6991   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6992   {
6993     GfxFrame[x][y] = 0;
6994   }
6995   else if (action_moving)
6996   {
6997     boolean is_backside = object_mapping[tile].is_backside;
6998
6999     if (is_backside)
7000     {
7001       int direction = object_mapping[tile].direction;
7002       int move_dir = (action_falling ? MV_DOWN : direction);
7003
7004       GfxFrame[x][y]++;
7005
7006 #if 1
7007       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7008       if (g->double_movement && frame_em == 0)
7009         GfxFrame[x][y] = 0;
7010 #endif
7011
7012       if (move_dir == MV_LEFT)
7013         GfxFrame[x - 1][y] = GfxFrame[x][y];
7014       else if (move_dir == MV_RIGHT)
7015         GfxFrame[x + 1][y] = GfxFrame[x][y];
7016       else if (move_dir == MV_UP)
7017         GfxFrame[x][y - 1] = GfxFrame[x][y];
7018       else if (move_dir == MV_DOWN)
7019         GfxFrame[x][y + 1] = GfxFrame[x][y];
7020     }
7021   }
7022   else
7023   {
7024     GfxFrame[x][y]++;
7025
7026     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7027     if (tile == Xsand_stonesand_quickout_1 ||
7028         tile == Xsand_stonesand_quickout_2)
7029       GfxFrame[x][y]++;
7030   }
7031
7032   if (graphic_info[graphic].anim_global_sync)
7033     sync_frame = FrameCounter;
7034   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7035     sync_frame = GfxFrame[x][y];
7036   else
7037     sync_frame = 0;     /* playfield border (pseudo steel) */
7038
7039   SetRandomAnimationValue(x, y);
7040
7041   int frame = getAnimationFrame(g->anim_frames,
7042                                 g->anim_delay,
7043                                 g->anim_mode,
7044                                 g->anim_start_frame,
7045                                 sync_frame);
7046
7047   g_em->unique_identifier =
7048     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7049 }
7050
7051 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7052                                   int tile, int frame_em, int x, int y)
7053 {
7054   int action = object_mapping[tile].action;
7055   int direction = object_mapping[tile].direction;
7056   boolean is_backside = object_mapping[tile].is_backside;
7057   int effective_element = get_effective_element_EM(tile, frame_em);
7058   int effective_action = action;
7059   int graphic = (direction == MV_NONE ?
7060                  el_act2img(effective_element, effective_action) :
7061                  el_act_dir2img(effective_element, effective_action,
7062                                 direction));
7063   int crumbled = (direction == MV_NONE ?
7064                   el_act2crm(effective_element, effective_action) :
7065                   el_act_dir2crm(effective_element, effective_action,
7066                                  direction));
7067   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7068   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7069   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7070   struct GraphicInfo *g = &graphic_info[graphic];
7071   int sync_frame;
7072
7073   /* special case: graphic uses "2nd movement tile" and has defined
7074      7 frames for movement animation (or less) => use default graphic
7075      for last (8th) frame which ends the movement animation */
7076   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7077   {
7078     effective_action = ACTION_DEFAULT;
7079     graphic = (direction == MV_NONE ?
7080                el_act2img(effective_element, effective_action) :
7081                el_act_dir2img(effective_element, effective_action,
7082                               direction));
7083     crumbled = (direction == MV_NONE ?
7084                 el_act2crm(effective_element, effective_action) :
7085                 el_act_dir2crm(effective_element, effective_action,
7086                                direction));
7087
7088     g = &graphic_info[graphic];
7089   }
7090
7091   if (graphic_info[graphic].anim_global_sync)
7092     sync_frame = FrameCounter;
7093   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7094     sync_frame = GfxFrame[x][y];
7095   else
7096     sync_frame = 0;     /* playfield border (pseudo steel) */
7097
7098   SetRandomAnimationValue(x, y);
7099
7100   int frame = getAnimationFrame(g->anim_frames,
7101                                 g->anim_delay,
7102                                 g->anim_mode,
7103                                 g->anim_start_frame,
7104                                 sync_frame);
7105
7106   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7107                       g->double_movement && is_backside);
7108
7109   /* (updating the "crumbled" graphic definitions is probably not really needed,
7110      as animations for crumbled graphics can't be longer than one EMC cycle) */
7111   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7112                            sync_frame);
7113 }
7114
7115 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7116                                   int player_nr, int anim, int frame_em)
7117 {
7118   int element   = player_mapping[player_nr][anim].element_rnd;
7119   int action    = player_mapping[player_nr][anim].action;
7120   int direction = player_mapping[player_nr][anim].direction;
7121   int graphic = (direction == MV_NONE ?
7122                  el_act2img(element, action) :
7123                  el_act_dir2img(element, action, direction));
7124   struct GraphicInfo *g = &graphic_info[graphic];
7125   int sync_frame;
7126
7127   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7128
7129   stored_player[player_nr].StepFrame = frame_em;
7130
7131   sync_frame = stored_player[player_nr].Frame;
7132
7133   int frame = getAnimationFrame(g->anim_frames,
7134                                 g->anim_delay,
7135                                 g->anim_mode,
7136                                 g->anim_start_frame,
7137                                 sync_frame);
7138
7139   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7140                       &g_em->src_x, &g_em->src_y, FALSE);
7141 }
7142
7143 void InitGraphicInfo_EM(void)
7144 {
7145   int i, j, p;
7146
7147 #if DEBUG_EM_GFX
7148   int num_em_gfx_errors = 0;
7149
7150   if (graphic_info_em_object[0][0].bitmap == NULL)
7151   {
7152     /* EM graphics not yet initialized in em_open_all() */
7153
7154     return;
7155   }
7156
7157   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7158 #endif
7159
7160   /* always start with reliable default values */
7161   for (i = 0; i < TILE_MAX; i++)
7162   {
7163     object_mapping[i].element_rnd = EL_UNKNOWN;
7164     object_mapping[i].is_backside = FALSE;
7165     object_mapping[i].action = ACTION_DEFAULT;
7166     object_mapping[i].direction = MV_NONE;
7167   }
7168
7169   /* always start with reliable default values */
7170   for (p = 0; p < MAX_PLAYERS; p++)
7171   {
7172     for (i = 0; i < SPR_MAX; i++)
7173     {
7174       player_mapping[p][i].element_rnd = EL_UNKNOWN;
7175       player_mapping[p][i].action = ACTION_DEFAULT;
7176       player_mapping[p][i].direction = MV_NONE;
7177     }
7178   }
7179
7180   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7181   {
7182     int e = em_object_mapping_list[i].element_em;
7183
7184     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7185     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7186
7187     if (em_object_mapping_list[i].action != -1)
7188       object_mapping[e].action = em_object_mapping_list[i].action;
7189
7190     if (em_object_mapping_list[i].direction != -1)
7191       object_mapping[e].direction =
7192         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7193   }
7194
7195   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7196   {
7197     int a = em_player_mapping_list[i].action_em;
7198     int p = em_player_mapping_list[i].player_nr;
7199
7200     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7201
7202     if (em_player_mapping_list[i].action != -1)
7203       player_mapping[p][a].action = em_player_mapping_list[i].action;
7204
7205     if (em_player_mapping_list[i].direction != -1)
7206       player_mapping[p][a].direction =
7207         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7208   }
7209
7210   for (i = 0; i < TILE_MAX; i++)
7211   {
7212     int element = object_mapping[i].element_rnd;
7213     int action = object_mapping[i].action;
7214     int direction = object_mapping[i].direction;
7215     boolean is_backside = object_mapping[i].is_backside;
7216     boolean action_exploding = ((action == ACTION_EXPLODING ||
7217                                  action == ACTION_SMASHED_BY_ROCK ||
7218                                  action == ACTION_SMASHED_BY_SPRING) &&
7219                                 element != EL_DIAMOND);
7220     boolean action_active = (action == ACTION_ACTIVE);
7221     boolean action_other = (action == ACTION_OTHER);
7222
7223     for (j = 0; j < 8; j++)
7224     {
7225       int effective_element = get_effective_element_EM(i, j);
7226       int effective_action = (j < 7 ? action :
7227                               i == Xdrip_stretch ? action :
7228                               i == Xdrip_stretchB ? action :
7229                               i == Ydrip_s1 ? action :
7230                               i == Ydrip_s1B ? action :
7231                               i == Xball_1B ? action :
7232                               i == Xball_2 ? action :
7233                               i == Xball_2B ? action :
7234                               i == Yball_eat ? action :
7235                               i == Ykey_1_eat ? action :
7236                               i == Ykey_2_eat ? action :
7237                               i == Ykey_3_eat ? action :
7238                               i == Ykey_4_eat ? action :
7239                               i == Ykey_5_eat ? action :
7240                               i == Ykey_6_eat ? action :
7241                               i == Ykey_7_eat ? action :
7242                               i == Ykey_8_eat ? action :
7243                               i == Ylenses_eat ? action :
7244                               i == Ymagnify_eat ? action :
7245                               i == Ygrass_eat ? action :
7246                               i == Ydirt_eat ? action :
7247                               i == Xsand_stonein_1 ? action :
7248                               i == Xsand_stonein_2 ? action :
7249                               i == Xsand_stonein_3 ? action :
7250                               i == Xsand_stonein_4 ? action :
7251                               i == Xsand_stoneout_1 ? action :
7252                               i == Xsand_stoneout_2 ? action :
7253                               i == Xboom_android ? ACTION_EXPLODING :
7254                               action_exploding ? ACTION_EXPLODING :
7255                               action_active ? action :
7256                               action_other ? action :
7257                               ACTION_DEFAULT);
7258       int graphic = (el_act_dir2img(effective_element, effective_action,
7259                                     direction));
7260       int crumbled = (el_act_dir2crm(effective_element, effective_action,
7261                                      direction));
7262       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7263       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7264       boolean has_action_graphics = (graphic != base_graphic);
7265       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7266       struct GraphicInfo *g = &graphic_info[graphic];
7267       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7268       Bitmap *src_bitmap;
7269       int src_x, src_y;
7270       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7271       boolean special_animation = (action != ACTION_DEFAULT &&
7272                                    g->anim_frames == 3 &&
7273                                    g->anim_delay == 2 &&
7274                                    g->anim_mode & ANIM_LINEAR);
7275       int sync_frame = (i == Xdrip_stretch ? 7 :
7276                         i == Xdrip_stretchB ? 7 :
7277                         i == Ydrip_s2 ? j + 8 :
7278                         i == Ydrip_s2B ? j + 8 :
7279                         i == Xacid_1 ? 0 :
7280                         i == Xacid_2 ? 10 :
7281                         i == Xacid_3 ? 20 :
7282                         i == Xacid_4 ? 30 :
7283                         i == Xacid_5 ? 40 :
7284                         i == Xacid_6 ? 50 :
7285                         i == Xacid_7 ? 60 :
7286                         i == Xacid_8 ? 70 :
7287                         i == Xfake_acid_1 ? 0 :
7288                         i == Xfake_acid_2 ? 10 :
7289                         i == Xfake_acid_3 ? 20 :
7290                         i == Xfake_acid_4 ? 30 :
7291                         i == Xfake_acid_5 ? 40 :
7292                         i == Xfake_acid_6 ? 50 :
7293                         i == Xfake_acid_7 ? 60 :
7294                         i == Xfake_acid_8 ? 70 :
7295                         i == Xball_2 ? 7 :
7296                         i == Xball_2B ? j + 8 :
7297                         i == Yball_eat ? j + 1 :
7298                         i == Ykey_1_eat ? j + 1 :
7299                         i == Ykey_2_eat ? j + 1 :
7300                         i == Ykey_3_eat ? j + 1 :
7301                         i == Ykey_4_eat ? j + 1 :
7302                         i == Ykey_5_eat ? j + 1 :
7303                         i == Ykey_6_eat ? j + 1 :
7304                         i == Ykey_7_eat ? j + 1 :
7305                         i == Ykey_8_eat ? j + 1 :
7306                         i == Ylenses_eat ? j + 1 :
7307                         i == Ymagnify_eat ? j + 1 :
7308                         i == Ygrass_eat ? j + 1 :
7309                         i == Ydirt_eat ? j + 1 :
7310                         i == Xamoeba_1 ? 0 :
7311                         i == Xamoeba_2 ? 1 :
7312                         i == Xamoeba_3 ? 2 :
7313                         i == Xamoeba_4 ? 3 :
7314                         i == Xamoeba_5 ? 0 :
7315                         i == Xamoeba_6 ? 1 :
7316                         i == Xamoeba_7 ? 2 :
7317                         i == Xamoeba_8 ? 3 :
7318                         i == Xexit_2 ? j + 8 :
7319                         i == Xexit_3 ? j + 16 :
7320                         i == Xdynamite_1 ? 0 :
7321                         i == Xdynamite_2 ? 8 :
7322                         i == Xdynamite_3 ? 16 :
7323                         i == Xdynamite_4 ? 24 :
7324                         i == Xsand_stonein_1 ? j + 1 :
7325                         i == Xsand_stonein_2 ? j + 9 :
7326                         i == Xsand_stonein_3 ? j + 17 :
7327                         i == Xsand_stonein_4 ? j + 25 :
7328                         i == Xsand_stoneout_1 && j == 0 ? 0 :
7329                         i == Xsand_stoneout_1 && j == 1 ? 0 :
7330                         i == Xsand_stoneout_1 && j == 2 ? 1 :
7331                         i == Xsand_stoneout_1 && j == 3 ? 2 :
7332                         i == Xsand_stoneout_1 && j == 4 ? 2 :
7333                         i == Xsand_stoneout_1 && j == 5 ? 3 :
7334                         i == Xsand_stoneout_1 && j == 6 ? 4 :
7335                         i == Xsand_stoneout_1 && j == 7 ? 4 :
7336                         i == Xsand_stoneout_2 && j == 0 ? 5 :
7337                         i == Xsand_stoneout_2 && j == 1 ? 6 :
7338                         i == Xsand_stoneout_2 && j == 2 ? 7 :
7339                         i == Xsand_stoneout_2 && j == 3 ? 8 :
7340                         i == Xsand_stoneout_2 && j == 4 ? 9 :
7341                         i == Xsand_stoneout_2 && j == 5 ? 11 :
7342                         i == Xsand_stoneout_2 && j == 6 ? 13 :
7343                         i == Xsand_stoneout_2 && j == 7 ? 15 :
7344                         i == Xboom_bug && j == 1 ? 2 :
7345                         i == Xboom_bug && j == 2 ? 2 :
7346                         i == Xboom_bug && j == 3 ? 4 :
7347                         i == Xboom_bug && j == 4 ? 4 :
7348                         i == Xboom_bug && j == 5 ? 2 :
7349                         i == Xboom_bug && j == 6 ? 2 :
7350                         i == Xboom_bug && j == 7 ? 0 :
7351                         i == Xboom_bomb && j == 1 ? 2 :
7352                         i == Xboom_bomb && j == 2 ? 2 :
7353                         i == Xboom_bomb && j == 3 ? 4 :
7354                         i == Xboom_bomb && j == 4 ? 4 :
7355                         i == Xboom_bomb && j == 5 ? 2 :
7356                         i == Xboom_bomb && j == 6 ? 2 :
7357                         i == Xboom_bomb && j == 7 ? 0 :
7358                         i == Xboom_android && j == 7 ? 6 :
7359                         i == Xboom_1 && j == 1 ? 2 :
7360                         i == Xboom_1 && j == 2 ? 2 :
7361                         i == Xboom_1 && j == 3 ? 4 :
7362                         i == Xboom_1 && j == 4 ? 4 :
7363                         i == Xboom_1 && j == 5 ? 6 :
7364                         i == Xboom_1 && j == 6 ? 6 :
7365                         i == Xboom_1 && j == 7 ? 8 :
7366                         i == Xboom_2 && j == 0 ? 8 :
7367                         i == Xboom_2 && j == 1 ? 8 :
7368                         i == Xboom_2 && j == 2 ? 10 :
7369                         i == Xboom_2 && j == 3 ? 10 :
7370                         i == Xboom_2 && j == 4 ? 10 :
7371                         i == Xboom_2 && j == 5 ? 12 :
7372                         i == Xboom_2 && j == 6 ? 12 :
7373                         i == Xboom_2 && j == 7 ? 12 :
7374                         special_animation && j == 4 ? 3 :
7375                         effective_action != action ? 0 :
7376                         j);
7377
7378 #if DEBUG_EM_GFX
7379       Bitmap *debug_bitmap = g_em->bitmap;
7380       int debug_src_x = g_em->src_x;
7381       int debug_src_y = g_em->src_y;
7382 #endif
7383
7384       int frame = getAnimationFrame(g->anim_frames,
7385                                     g->anim_delay,
7386                                     g->anim_mode,
7387                                     g->anim_start_frame,
7388                                     sync_frame);
7389
7390       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7391                           g->double_movement && is_backside);
7392
7393       g_em->bitmap = src_bitmap;
7394       g_em->src_x = src_x;
7395       g_em->src_y = src_y;
7396       g_em->src_offset_x = 0;
7397       g_em->src_offset_y = 0;
7398       g_em->dst_offset_x = 0;
7399       g_em->dst_offset_y = 0;
7400       g_em->width  = TILEX;
7401       g_em->height = TILEY;
7402
7403       g_em->preserve_background = FALSE;
7404
7405       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7406                                sync_frame);
7407
7408       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7409                                    effective_action == ACTION_MOVING  ||
7410                                    effective_action == ACTION_PUSHING ||
7411                                    effective_action == ACTION_EATING)) ||
7412           (!has_action_graphics && (effective_action == ACTION_FILLING ||
7413                                     effective_action == ACTION_EMPTYING)))
7414       {
7415         int move_dir =
7416           (effective_action == ACTION_FALLING ||
7417            effective_action == ACTION_FILLING ||
7418            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7419         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7420         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
7421         int num_steps = (i == Ydrip_s1  ? 16 :
7422                          i == Ydrip_s1B ? 16 :
7423                          i == Ydrip_s2  ? 16 :
7424                          i == Ydrip_s2B ? 16 :
7425                          i == Xsand_stonein_1 ? 32 :
7426                          i == Xsand_stonein_2 ? 32 :
7427                          i == Xsand_stonein_3 ? 32 :
7428                          i == Xsand_stonein_4 ? 32 :
7429                          i == Xsand_stoneout_1 ? 16 :
7430                          i == Xsand_stoneout_2 ? 16 : 8);
7431         int cx = ABS(dx) * (TILEX / num_steps);
7432         int cy = ABS(dy) * (TILEY / num_steps);
7433         int step_frame = (i == Ydrip_s2         ? j + 8 :
7434                           i == Ydrip_s2B        ? j + 8 :
7435                           i == Xsand_stonein_2  ? j + 8 :
7436                           i == Xsand_stonein_3  ? j + 16 :
7437                           i == Xsand_stonein_4  ? j + 24 :
7438                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7439         int step = (is_backside ? step_frame : num_steps - step_frame);
7440
7441         if (is_backside)        /* tile where movement starts */
7442         {
7443           if (dx < 0 || dy < 0)
7444           {
7445             g_em->src_offset_x = cx * step;
7446             g_em->src_offset_y = cy * step;
7447           }
7448           else
7449           {
7450             g_em->dst_offset_x = cx * step;
7451             g_em->dst_offset_y = cy * step;
7452           }
7453         }
7454         else                    /* tile where movement ends */
7455         {
7456           if (dx < 0 || dy < 0)
7457           {
7458             g_em->dst_offset_x = cx * step;
7459             g_em->dst_offset_y = cy * step;
7460           }
7461           else
7462           {
7463             g_em->src_offset_x = cx * step;
7464             g_em->src_offset_y = cy * step;
7465           }
7466         }
7467
7468         g_em->width  = TILEX - cx * step;
7469         g_em->height = TILEY - cy * step;
7470       }
7471
7472       /* create unique graphic identifier to decide if tile must be redrawn */
7473       /* bit 31 - 16 (16 bit): EM style graphic
7474          bit 15 - 12 ( 4 bit): EM style frame
7475          bit 11 -  6 ( 6 bit): graphic width
7476          bit  5 -  0 ( 6 bit): graphic height */
7477       g_em->unique_identifier =
7478         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7479
7480 #if DEBUG_EM_GFX
7481
7482       /* skip check for EMC elements not contained in original EMC artwork */
7483       if (element == EL_EMC_FAKE_ACID)
7484         continue;
7485
7486       if (g_em->bitmap != debug_bitmap ||
7487           g_em->src_x != debug_src_x ||
7488           g_em->src_y != debug_src_y ||
7489           g_em->src_offset_x != 0 ||
7490           g_em->src_offset_y != 0 ||
7491           g_em->dst_offset_x != 0 ||
7492           g_em->dst_offset_y != 0 ||
7493           g_em->width != TILEX ||
7494           g_em->height != TILEY)
7495       {
7496         static int last_i = -1;
7497
7498         if (i != last_i)
7499         {
7500           printf("\n");
7501           last_i = i;
7502         }
7503
7504         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7505                i, element, element_info[element].token_name,
7506                element_action_info[effective_action].suffix, direction);
7507
7508         if (element != effective_element)
7509           printf(" [%d ('%s')]",
7510                  effective_element,
7511                  element_info[effective_element].token_name);
7512
7513         printf("\n");
7514
7515         if (g_em->bitmap != debug_bitmap)
7516           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7517                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7518
7519         if (g_em->src_x != debug_src_x ||
7520             g_em->src_y != debug_src_y)
7521           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7522                  j, (is_backside ? 'B' : 'F'),
7523                  g_em->src_x, g_em->src_y,
7524                  g_em->src_x / 32, g_em->src_y / 32,
7525                  debug_src_x, debug_src_y,
7526                  debug_src_x / 32, debug_src_y / 32);
7527
7528         if (g_em->src_offset_x != 0 ||
7529             g_em->src_offset_y != 0 ||
7530             g_em->dst_offset_x != 0 ||
7531             g_em->dst_offset_y != 0)
7532           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7533                  j, is_backside,
7534                  g_em->src_offset_x, g_em->src_offset_y,
7535                  g_em->dst_offset_x, g_em->dst_offset_y);
7536
7537         if (g_em->width != TILEX ||
7538             g_em->height != TILEY)
7539           printf("    %d (%d): size %d,%d should be %d,%d\n",
7540                  j, is_backside,
7541                  g_em->width, g_em->height, TILEX, TILEY);
7542
7543         num_em_gfx_errors++;
7544       }
7545 #endif
7546
7547     }
7548   }
7549
7550   for (i = 0; i < TILE_MAX; i++)
7551   {
7552     for (j = 0; j < 8; j++)
7553     {
7554       int element = object_mapping[i].element_rnd;
7555       int action = object_mapping[i].action;
7556       int direction = object_mapping[i].direction;
7557       boolean is_backside = object_mapping[i].is_backside;
7558       int graphic_action  = el_act_dir2img(element, action, direction);
7559       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7560
7561       if ((action == ACTION_SMASHED_BY_ROCK ||
7562            action == ACTION_SMASHED_BY_SPRING ||
7563            action == ACTION_EATING) &&
7564           graphic_action == graphic_default)
7565       {
7566         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
7567                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7568                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
7569                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7570                  Xspring);
7571
7572         /* no separate animation for "smashed by rock" -- use rock instead */
7573         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7574         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7575
7576         g_em->bitmap            = g_xx->bitmap;
7577         g_em->src_x             = g_xx->src_x;
7578         g_em->src_y             = g_xx->src_y;
7579         g_em->src_offset_x      = g_xx->src_offset_x;
7580         g_em->src_offset_y      = g_xx->src_offset_y;
7581         g_em->dst_offset_x      = g_xx->dst_offset_x;
7582         g_em->dst_offset_y      = g_xx->dst_offset_y;
7583         g_em->width             = g_xx->width;
7584         g_em->height            = g_xx->height;
7585         g_em->unique_identifier = g_xx->unique_identifier;
7586
7587         if (!is_backside)
7588           g_em->preserve_background = TRUE;
7589       }
7590     }
7591   }
7592
7593   for (p = 0; p < MAX_PLAYERS; p++)
7594   {
7595     for (i = 0; i < SPR_MAX; i++)
7596     {
7597       int element = player_mapping[p][i].element_rnd;
7598       int action = player_mapping[p][i].action;
7599       int direction = player_mapping[p][i].direction;
7600
7601       for (j = 0; j < 8; j++)
7602       {
7603         int effective_element = element;
7604         int effective_action = action;
7605         int graphic = (direction == MV_NONE ?
7606                        el_act2img(effective_element, effective_action) :
7607                        el_act_dir2img(effective_element, effective_action,
7608                                       direction));
7609         struct GraphicInfo *g = &graphic_info[graphic];
7610         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7611         Bitmap *src_bitmap;
7612         int src_x, src_y;
7613         int sync_frame = j;
7614
7615 #if DEBUG_EM_GFX
7616         Bitmap *debug_bitmap = g_em->bitmap;
7617         int debug_src_x = g_em->src_x;
7618         int debug_src_y = g_em->src_y;
7619 #endif
7620
7621         int frame = getAnimationFrame(g->anim_frames,
7622                                       g->anim_delay,
7623                                       g->anim_mode,
7624                                       g->anim_start_frame,
7625                                       sync_frame);
7626
7627         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7628
7629         g_em->bitmap = src_bitmap;
7630         g_em->src_x = src_x;
7631         g_em->src_y = src_y;
7632         g_em->src_offset_x = 0;
7633         g_em->src_offset_y = 0;
7634         g_em->dst_offset_x = 0;
7635         g_em->dst_offset_y = 0;
7636         g_em->width  = TILEX;
7637         g_em->height = TILEY;
7638
7639 #if DEBUG_EM_GFX
7640
7641         /* skip check for EMC elements not contained in original EMC artwork */
7642         if (element == EL_PLAYER_3 ||
7643             element == EL_PLAYER_4)
7644           continue;
7645
7646         if (g_em->bitmap != debug_bitmap ||
7647             g_em->src_x != debug_src_x ||
7648             g_em->src_y != debug_src_y)
7649         {
7650           static int last_i = -1;
7651
7652           if (i != last_i)
7653           {
7654             printf("\n");
7655             last_i = i;
7656           }
7657
7658           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7659                  p, i, element, element_info[element].token_name,
7660                  element_action_info[effective_action].suffix, direction);
7661
7662           if (element != effective_element)
7663             printf(" [%d ('%s')]",
7664                    effective_element,
7665                    element_info[effective_element].token_name);
7666
7667           printf("\n");
7668
7669           if (g_em->bitmap != debug_bitmap)
7670             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
7671                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
7672
7673           if (g_em->src_x != debug_src_x ||
7674               g_em->src_y != debug_src_y)
7675             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7676                    j,
7677                    g_em->src_x, g_em->src_y,
7678                    g_em->src_x / 32, g_em->src_y / 32,
7679                    debug_src_x, debug_src_y,
7680                    debug_src_x / 32, debug_src_y / 32);
7681
7682           num_em_gfx_errors++;
7683         }
7684 #endif
7685
7686       }
7687     }
7688   }
7689
7690 #if DEBUG_EM_GFX
7691   printf("\n");
7692   printf("::: [%d errors found]\n", num_em_gfx_errors);
7693
7694   exit(0);
7695 #endif
7696 }
7697
7698 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7699                                 boolean any_player_moving,
7700                                 boolean any_player_snapping,
7701                                 boolean any_player_dropping)
7702 {
7703   static boolean player_was_waiting = TRUE;
7704
7705   if (frame == 0 && !any_player_dropping)
7706   {
7707     if (!player_was_waiting)
7708     {
7709       if (!SaveEngineSnapshotToList())
7710         return;
7711
7712       player_was_waiting = TRUE;
7713     }
7714   }
7715   else if (any_player_moving || any_player_snapping || any_player_dropping)
7716   {
7717     player_was_waiting = FALSE;
7718   }
7719 }
7720
7721 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7722                                 boolean murphy_is_dropping)
7723 {
7724   static boolean player_was_waiting = TRUE;
7725
7726   if (murphy_is_waiting)
7727   {
7728     if (!player_was_waiting)
7729     {
7730       if (!SaveEngineSnapshotToList())
7731         return;
7732
7733       player_was_waiting = TRUE;
7734     }
7735   }
7736   else
7737   {
7738     player_was_waiting = FALSE;
7739   }
7740 }
7741
7742 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7743                             boolean any_player_moving,
7744                             boolean any_player_snapping,
7745                             boolean any_player_dropping)
7746 {
7747   if (tape.single_step && tape.recording && !tape.pausing)
7748     if (frame == 0 && !any_player_dropping)
7749       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7750
7751   CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7752                              any_player_snapping, any_player_dropping);
7753 }
7754
7755 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7756                             boolean murphy_is_dropping)
7757 {
7758   if (tape.single_step && tape.recording && !tape.pausing)
7759     if (murphy_is_waiting)
7760       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7761
7762   CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7763 }
7764
7765 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7766                          int graphic, int sync_frame, int x, int y)
7767 {
7768   int frame = getGraphicAnimationFrame(graphic, sync_frame);
7769
7770   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7771 }
7772
7773 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7774 {
7775   return (IS_NEXT_FRAME(sync_frame, graphic));
7776 }
7777
7778 int getGraphicInfo_Delay(int graphic)
7779 {
7780   return graphic_info[graphic].anim_delay;
7781 }
7782
7783 void PlayMenuSoundExt(int sound)
7784 {
7785   if (sound == SND_UNDEFINED)
7786     return;
7787
7788   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7789       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7790     return;
7791
7792   if (IS_LOOP_SOUND(sound))
7793     PlaySoundLoop(sound);
7794   else
7795     PlaySound(sound);
7796 }
7797
7798 void PlayMenuSound()
7799 {
7800   PlayMenuSoundExt(menu.sound[game_status]);
7801 }
7802
7803 void PlayMenuSoundStereo(int sound, int stereo_position)
7804 {
7805   if (sound == SND_UNDEFINED)
7806     return;
7807
7808   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7809       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7810     return;
7811
7812   if (IS_LOOP_SOUND(sound))
7813     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7814   else
7815     PlaySoundStereo(sound, stereo_position);
7816 }
7817
7818 void PlayMenuSoundIfLoopExt(int sound)
7819 {
7820   if (sound == SND_UNDEFINED)
7821     return;
7822
7823   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7824       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7825     return;
7826
7827   if (IS_LOOP_SOUND(sound))
7828     PlaySoundLoop(sound);
7829 }
7830
7831 void PlayMenuSoundIfLoop()
7832 {
7833   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7834 }
7835
7836 void PlayMenuMusicExt(int music)
7837 {
7838   if (music == MUS_UNDEFINED)
7839     return;
7840
7841   if (!setup.sound_music)
7842     return;
7843
7844   PlayMusic(music);
7845 }
7846
7847 void PlayMenuMusic()
7848 {
7849   PlayMenuMusicExt(menu.music[game_status]);
7850 }
7851
7852 void PlaySoundActivating()
7853 {
7854 #if 0
7855   PlaySound(SND_MENU_ITEM_ACTIVATING);
7856 #endif
7857 }
7858
7859 void PlaySoundSelecting()
7860 {
7861 #if 0
7862   PlaySound(SND_MENU_ITEM_SELECTING);
7863 #endif
7864 }
7865
7866 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7867 {
7868   boolean change_fullscreen = (setup.fullscreen !=
7869                                video.fullscreen_enabled);
7870   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7871                                     !strEqual(setup.fullscreen_mode,
7872                                               video.fullscreen_mode_current));
7873   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7874                                            setup.window_scaling_percent !=
7875                                            video.window_scaling_percent);
7876
7877   if (change_window_scaling_percent && video.fullscreen_enabled)
7878     return;
7879
7880   if (!change_window_scaling_percent && !video.fullscreen_available)
7881     return;
7882
7883 #if defined(TARGET_SDL2)
7884   if (change_window_scaling_percent)
7885   {
7886     SDLSetWindowScaling(setup.window_scaling_percent);
7887
7888     return;
7889   }
7890   else if (change_fullscreen)
7891   {
7892     SDLSetWindowFullscreen(setup.fullscreen);
7893
7894     /* set setup value according to successfully changed fullscreen mode */
7895     setup.fullscreen = video.fullscreen_enabled;
7896
7897     return;
7898   }
7899 #endif
7900
7901   if (change_fullscreen ||
7902       change_fullscreen_mode ||
7903       change_window_scaling_percent)
7904   {
7905     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7906
7907     /* save backbuffer content which gets lost when toggling fullscreen mode */
7908     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7909
7910     if (change_fullscreen_mode)
7911     {
7912       /* keep fullscreen, but change fullscreen mode (screen resolution) */
7913       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
7914     }
7915
7916     if (change_window_scaling_percent)
7917     {
7918       /* keep window mode, but change window scaling */
7919       video.fullscreen_enabled = TRUE;          /* force new window scaling */
7920     }
7921
7922     /* toggle fullscreen */
7923     ChangeVideoModeIfNeeded(setup.fullscreen);
7924
7925     /* set setup value according to successfully changed fullscreen mode */
7926     setup.fullscreen = video.fullscreen_enabled;
7927
7928     /* restore backbuffer content from temporary backbuffer backup bitmap */
7929     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7930
7931     FreeBitmap(tmp_backbuffer);
7932
7933     /* update visible window/screen */
7934     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7935   }
7936 }
7937
7938 void ChangeViewportPropertiesIfNeeded()
7939 {
7940   int gfx_game_mode = game_status;
7941   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7942                         game_status);
7943   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7944   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7945   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7946   struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7947   int border_size       = vp_playfield->border_size;
7948   int new_sx            = vp_playfield->x + border_size;
7949   int new_sy            = vp_playfield->y + border_size;
7950   int new_sxsize        = vp_playfield->width  - 2 * border_size;
7951   int new_sysize        = vp_playfield->height - 2 * border_size;
7952   int new_real_sx       = vp_playfield->x;
7953   int new_real_sy       = vp_playfield->y;
7954   int new_full_sxsize   = vp_playfield->width;
7955   int new_full_sysize   = vp_playfield->height;
7956   int new_dx            = vp_door_1->x;
7957   int new_dy            = vp_door_1->y;
7958   int new_dxsize        = vp_door_1->width;
7959   int new_dysize        = vp_door_1->height;
7960   int new_vx            = vp_door_2->x;
7961   int new_vy            = vp_door_2->y;
7962   int new_vxsize        = vp_door_2->width;
7963   int new_vysize        = vp_door_2->height;
7964   int new_ex            = vp_door_3->x;
7965   int new_ey            = vp_door_3->y;
7966   int new_exsize        = vp_door_3->width;
7967   int new_eysize        = vp_door_3->height;
7968   int new_tilesize_var =
7969     (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7970
7971   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7972                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7973   int new_scr_fieldx = new_sxsize / tilesize;
7974   int new_scr_fieldy = new_sysize / tilesize;
7975   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7976   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7977   boolean init_gfx_buffers = FALSE;
7978   boolean init_video_buffer = FALSE;
7979   boolean init_gadgets_and_toons = FALSE;
7980   boolean init_em_graphics = FALSE;
7981   boolean drawing_area_changed = FALSE;
7982
7983   if (viewport.window.width  != WIN_XSIZE ||
7984       viewport.window.height != WIN_YSIZE)
7985   {
7986     WIN_XSIZE = viewport.window.width;
7987     WIN_YSIZE = viewport.window.height;
7988
7989     init_video_buffer = TRUE;
7990     init_gfx_buffers = TRUE;
7991
7992     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7993   }
7994
7995   if (new_scr_fieldx != SCR_FIELDX ||
7996       new_scr_fieldy != SCR_FIELDY)
7997   {
7998     /* this always toggles between MAIN and GAME when using small tile size */
7999
8000     SCR_FIELDX = new_scr_fieldx;
8001     SCR_FIELDY = new_scr_fieldy;
8002
8003     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8004   }
8005
8006   if (new_sx != SX ||
8007       new_sy != SY ||
8008       new_dx != DX ||
8009       new_dy != DY ||
8010       new_vx != VX ||
8011       new_vy != VY ||
8012       new_ex != EX ||
8013       new_ey != EY ||
8014       new_sxsize != SXSIZE ||
8015       new_sysize != SYSIZE ||
8016       new_dxsize != DXSIZE ||
8017       new_dysize != DYSIZE ||
8018       new_vxsize != VXSIZE ||
8019       new_vysize != VYSIZE ||
8020       new_exsize != EXSIZE ||
8021       new_eysize != EYSIZE ||
8022       new_real_sx != REAL_SX ||
8023       new_real_sy != REAL_SY ||
8024       new_full_sxsize != FULL_SXSIZE ||
8025       new_full_sysize != FULL_SYSIZE ||
8026       new_tilesize_var != TILESIZE_VAR
8027       )
8028   {
8029     if (new_tilesize_var != TILESIZE_VAR)
8030     {
8031       // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8032
8033       // changing tile size invalidates scroll values of engine snapshots
8034       FreeEngineSnapshotSingle();
8035
8036       // changing tile size requires update of graphic mapping for EM engine
8037       init_em_graphics = TRUE;
8038     }
8039
8040     if (new_sx != SX ||
8041         new_sy != SY ||
8042         new_sxsize != SXSIZE ||
8043         new_sysize != SYSIZE ||
8044         new_real_sx != REAL_SX ||
8045         new_real_sy != REAL_SY ||
8046         new_full_sxsize != FULL_SXSIZE ||
8047         new_full_sysize != FULL_SYSIZE)
8048     {
8049       if (!init_video_buffer)
8050         drawing_area_changed = TRUE;
8051     }
8052
8053     SX = new_sx;
8054     SY = new_sy;
8055     DX = new_dx;
8056     DY = new_dy;
8057     VX = new_vx;
8058     VY = new_vy;
8059     EX = new_ex;
8060     EY = new_ey;
8061     SXSIZE = new_sxsize;
8062     SYSIZE = new_sysize;
8063     DXSIZE = new_dxsize;
8064     DYSIZE = new_dysize;
8065     VXSIZE = new_vxsize;
8066     VYSIZE = new_vysize;
8067     EXSIZE = new_exsize;
8068     EYSIZE = new_eysize;
8069     REAL_SX = new_real_sx;
8070     REAL_SY = new_real_sy;
8071     FULL_SXSIZE = new_full_sxsize;
8072     FULL_SYSIZE = new_full_sysize;
8073     TILESIZE_VAR = new_tilesize_var;
8074
8075     init_gfx_buffers = TRUE;
8076     init_gadgets_and_toons = TRUE;
8077
8078     // printf("::: viewports: init_gfx_buffers\n");
8079     // printf("::: viewports: init_gadgets_and_toons\n");
8080   }
8081
8082   if (init_gfx_buffers)
8083   {
8084     // printf("::: init_gfx_buffers\n");
8085
8086     SCR_FIELDX = new_scr_fieldx_buffers;
8087     SCR_FIELDY = new_scr_fieldy_buffers;
8088
8089     InitGfxBuffers();
8090
8091     SCR_FIELDX = new_scr_fieldx;
8092     SCR_FIELDY = new_scr_fieldy;
8093
8094     gfx.drawing_area_changed = drawing_area_changed;
8095
8096     SetDrawDeactivationMask(REDRAW_NONE);
8097     SetDrawBackgroundMask(REDRAW_FIELD);
8098   }
8099
8100   if (init_video_buffer)
8101   {
8102     // printf("::: init_video_buffer\n");
8103
8104     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8105   }
8106
8107   if (init_gadgets_and_toons)
8108   {
8109     // printf("::: init_gadgets_and_toons\n");
8110
8111     InitGadgets();
8112     InitToons();
8113   }
8114
8115   if (init_em_graphics)
8116   {
8117       InitGraphicInfo_EM();
8118   }
8119 }