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