c6c5acf8c660eabdecc39a9e6aed4495a674f2bb
[rocksndiamonds.git] / src / tools.c
1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back!               *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include <math.h>
15
16 #include "libgame/libgame.h"
17
18 #include "tools.h"
19 #include "init.h"
20 #include "game.h"
21 #include "events.h"
22 #include "cartoons.h"
23 #include "network.h"
24 #include "tape.h"
25 #include "screens.h"
26
27
28 /* select level set with EMC X11 graphics before activating EM GFX debugging */
29 #define DEBUG_EM_GFX    0
30
31 /* tool button identifiers */
32 #define TOOL_CTRL_ID_YES        0
33 #define TOOL_CTRL_ID_NO         1
34 #define TOOL_CTRL_ID_CONFIRM    2
35 #define TOOL_CTRL_ID_PLAYER_1   3
36 #define TOOL_CTRL_ID_PLAYER_2   4
37 #define TOOL_CTRL_ID_PLAYER_3   5
38 #define TOOL_CTRL_ID_PLAYER_4   6
39
40 #define NUM_TOOL_BUTTONS        7
41
42 /* constants for number of doors and door parts */
43 #define NUM_DOORS               2
44 #define NUM_PANELS              NUM_DOORS
45 // #define NUM_PANELS           0
46 #define MAX_PARTS_PER_DOOR      8
47 #define MAX_DOOR_PARTS          (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
48 #define DOOR_PART_IS_PANEL(i)   ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49
50
51 struct DoorPartOrderInfo
52 {
53   int nr;
54   int sort_priority;
55 };
56
57 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
58
59 struct DoorPartControlInfo
60 {
61   int door_token;
62   int graphic;
63   struct DoorPartPosInfo *pos;
64 };
65
66 static struct DoorPartControlInfo door_part_controls[] =
67 {
68   {
69     DOOR_1,
70     IMG_DOOR_1_GFX_PART_1,
71     &door_1.part_1
72   },
73   {
74     DOOR_1,
75     IMG_DOOR_1_GFX_PART_2,
76     &door_1.part_2
77   },
78   {
79     DOOR_1,
80     IMG_DOOR_1_GFX_PART_3,
81     &door_1.part_3
82   },
83   {
84     DOOR_1,
85     IMG_DOOR_1_GFX_PART_4,
86     &door_1.part_4
87   },
88   {
89     DOOR_1,
90     IMG_DOOR_1_GFX_PART_5,
91     &door_1.part_5
92   },
93   {
94     DOOR_1,
95     IMG_DOOR_1_GFX_PART_6,
96     &door_1.part_6
97   },
98   {
99     DOOR_1,
100     IMG_DOOR_1_GFX_PART_7,
101     &door_1.part_7
102   },
103   {
104     DOOR_1,
105     IMG_DOOR_1_GFX_PART_8,
106     &door_1.part_8
107   },
108
109   {
110     DOOR_2,
111     IMG_DOOR_2_GFX_PART_1,
112     &door_2.part_1
113   },
114   {
115     DOOR_2,
116     IMG_DOOR_2_GFX_PART_2,
117     &door_2.part_2
118   },
119   {
120     DOOR_2,
121     IMG_DOOR_2_GFX_PART_3,
122     &door_2.part_3
123   },
124   {
125     DOOR_2,
126     IMG_DOOR_2_GFX_PART_4,
127     &door_2.part_4
128   },
129   {
130     DOOR_2,
131     IMG_DOOR_2_GFX_PART_5,
132     &door_2.part_5
133   },
134   {
135     DOOR_2,
136     IMG_DOOR_2_GFX_PART_6,
137     &door_2.part_6
138   },
139   {
140     DOOR_2,
141     IMG_DOOR_2_GFX_PART_7,
142     &door_2.part_7
143   },
144   {
145     DOOR_2,
146     IMG_DOOR_2_GFX_PART_8,
147     &door_2.part_8
148   },
149
150   {
151     DOOR_1,
152     IMG_BACKGROUND_PANEL,
153     &door_1.panel
154   },
155   {
156     DOOR_2,
157     IMG_BACKGROUND_TAPE,
158     &door_2.panel
159   },
160
161   {
162     -1,
163     -1,
164     NULL
165   }
166 };
167
168
169 /* forward declaration for internal use */
170 static void UnmapToolButtons();
171 static void HandleToolButtons(struct GadgetInfo *);
172 static int el_act_dir2crm(int, int, int);
173 static int el_act2crm(int, int);
174
175 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
176 static int request_gadget_id = -1;
177
178 static char *print_if_not_empty(int element)
179 {
180   static char *s = NULL;
181   char *token_name = element_info[element].token_name;
182
183   if (s != NULL)
184     free(s);
185
186   s = checked_malloc(strlen(token_name) + 10 + 1);
187
188   if (element != EL_EMPTY)
189     sprintf(s, "%d\t['%s']", element, token_name);
190   else
191     sprintf(s, "%d", element);
192
193   return s;
194 }
195
196 void DumpTile(int x, int y)
197 {
198   int sx = SCREENX(x);
199   int sy = SCREENY(y);
200
201   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
202   {
203     x--;
204     y--;
205   }
206
207   printf_line("-", 79);
208   printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
209   printf_line("-", 79);
210
211   if (!IN_LEV_FIELD(x, y))
212   {
213     printf("(not in level field)\n");
214     printf("\n");
215
216     return;
217   }
218
219   printf("  Feld:        %d\t['%s']\n", Feld[x][y],
220          element_info[Feld[x][y]].token_name);
221   printf("  Back:        %s\n", print_if_not_empty(Back[x][y]));
222   printf("  Store:       %s\n", print_if_not_empty(Store[x][y]));
223   printf("  Store2:      %s\n", print_if_not_empty(Store2[x][y]));
224   printf("  StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
225   printf("  MovPos:      %d\n", MovPos[x][y]);
226   printf("  MovDir:      %d\n", MovDir[x][y]);
227   printf("  MovDelay:    %d\n", MovDelay[x][y]);
228   printf("  ChangeDelay: %d\n", ChangeDelay[x][y]);
229   printf("  CustomValue: %d\n", CustomValue[x][y]);
230   printf("  GfxElement:  %d\n", GfxElement[x][y]);
231   printf("  GfxAction:   %d\n", GfxAction[x][y]);
232   printf("  GfxFrame:    %d\n", GfxFrame[x][y]);
233   printf("\n");
234 }
235
236 void SetDrawtoField(int mode)
237 {
238   if (mode == DRAW_BUFFERED && setup.soft_scrolling)
239   {
240 #if NEW_TILESIZE
241 #if NEW_SCROLL
242     FX = 2 * TILEX_VAR;
243     FY = 2 * TILEY_VAR;
244     BX1 = -2;
245     BY1 = -2;
246     BX2 = SCR_FIELDX + 1;
247     BY2 = SCR_FIELDY + 1;
248     redraw_x1 = 2;
249     redraw_y1 = 2;
250 #else
251     FX = TILEX_VAR;
252     FY = TILEY_VAR;
253     BX1 = -1;
254     BY1 = -1;
255     BX2 = SCR_FIELDX;
256     BY2 = SCR_FIELDY;
257     redraw_x1 = 1;
258     redraw_y1 = 1;
259 #endif
260 #else
261 #if NEW_SCROLL
262     FX = 2 * TILEX;
263     FY = 2 * TILEY;
264     BX1 = -2;
265     BY1 = -2;
266     BX2 = SCR_FIELDX + 1;
267     BY2 = SCR_FIELDY + 1;
268     redraw_x1 = 2;
269     redraw_y1 = 2;
270 #else
271     FX = TILEX;
272     FY = TILEY;
273     BX1 = -1;
274     BY1 = -1;
275     BX2 = SCR_FIELDX;
276     BY2 = SCR_FIELDY;
277     redraw_x1 = 1;
278     redraw_y1 = 1;
279 #endif
280 #endif
281
282     drawto_field = fieldbuffer;
283   }
284   else  /* DRAW_BACKBUFFER */
285   {
286     FX = SX;
287     FY = SY;
288     BX1 = 0;
289     BY1 = 0;
290     BX2 = SCR_FIELDX - 1;
291     BY2 = SCR_FIELDY - 1;
292     redraw_x1 = 0;
293     redraw_y1 = 0;
294
295     drawto_field = backbuffer;
296   }
297 }
298
299 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
300 {
301   if (game_status == GAME_MODE_PLAYING &&
302       level.game_engine_type == GAME_ENGINE_TYPE_EM)
303   {
304     /* currently there is no partial redraw -- always redraw whole playfield */
305     RedrawPlayfield_EM(TRUE);
306
307     /* blit playfield from scroll buffer to normal back buffer for fading in */
308     BlitScreenToBitmap_EM(backbuffer);
309   }
310   else if (game_status == GAME_MODE_PLAYING &&
311            level.game_engine_type == GAME_ENGINE_TYPE_SP)
312   {
313     /* currently there is no partial redraw -- always redraw whole playfield */
314     RedrawPlayfield_SP(TRUE);
315
316     /* blit playfield from scroll buffer to normal back buffer for fading in */
317     BlitScreenToBitmap_SP(backbuffer);
318   }
319   else if (game_status == GAME_MODE_PLAYING &&
320            !game.envelope_active)
321   {
322     if (force_redraw)
323     {
324       x = gfx.sx - TILEX;
325       y = gfx.sy - TILEY;
326       width = gfx.sxsize + 2 * TILEX;
327       height = gfx.sysize + 2 * TILEY;
328     }
329
330     if (force_redraw)
331     {
332       int xx, yy;
333       int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
334       int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
335
336       for (xx = BX1; xx <= BX2; xx++)
337         for (yy = BY1; yy <= BY2; yy++)
338           if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
339             DrawScreenField(xx, yy);
340       DrawAllPlayers();
341     }
342
343     if (setup.soft_scrolling)
344     {
345       int fx = FX, fy = FY;
346
347       fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
348       fy += (ScreenMovDir & (MV_UP|MV_DOWN)    ? ScreenGfxPos : 0);
349
350       BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
351     }
352   }
353
354   if (force_redraw)
355   {
356     x = gfx.sx;
357     y = gfx.sy;
358     width = gfx.sxsize;
359     height = gfx.sysize;
360   }
361
362   BlitBitmap(drawto, window, x, y, width, height, x, y);
363 }
364
365 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
366 {
367   Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
368
369   SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
370   BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
371 }
372
373 void DrawMaskedBorder_FIELD()
374 {
375   if (global.border_status >= GAME_MODE_TITLE &&
376       global.border_status <= GAME_MODE_PLAYING &&
377       border.draw_masked[global.border_status])
378     DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
379 }
380
381 void DrawMaskedBorder_DOOR_1()
382 {
383   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
384       (global.border_status != GAME_MODE_EDITOR ||
385        border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
386     DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
387 }
388
389 void DrawMaskedBorder_DOOR_2()
390 {
391   if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
392       global.border_status != GAME_MODE_EDITOR)
393     DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
394 }
395
396 void DrawMaskedBorder_DOOR_3()
397 {
398   /* currently not available */
399 }
400
401 void DrawMaskedBorder_ALL()
402 {
403   DrawMaskedBorder_FIELD();
404   DrawMaskedBorder_DOOR_1();
405   DrawMaskedBorder_DOOR_2();
406   DrawMaskedBorder_DOOR_3();
407 }
408
409 void DrawMaskedBorder(int redraw_mask)
410 {
411   /* never draw masked screen borders on borderless screens */
412   if (effectiveGameStatus() == GAME_MODE_LOADING ||
413       effectiveGameStatus() == GAME_MODE_TITLE)
414     return;
415
416   /* never draw masked screen borders when displaying request outside door */
417   if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
418       global.use_envelope_request)
419     return;
420
421   if (redraw_mask & REDRAW_ALL)
422     DrawMaskedBorder_ALL();
423   else
424   {
425     if (redraw_mask & REDRAW_FIELD)
426       DrawMaskedBorder_FIELD();
427     if (redraw_mask & REDRAW_DOOR_1)
428       DrawMaskedBorder_DOOR_1();
429     if (redraw_mask & REDRAW_DOOR_2)
430       DrawMaskedBorder_DOOR_2();
431     if (redraw_mask & REDRAW_DOOR_3)
432       DrawMaskedBorder_DOOR_3();
433   }
434 }
435
436 void BlitScreenToBitmap(Bitmap *target_bitmap)
437 {
438   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
439   int fx = FX, fy = FY;
440
441 #if NEW_TILESIZE
442   int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
443   int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
444   int dx_var = dx * TILESIZE_VAR / TILESIZE;
445   int dy_var = dy * TILESIZE_VAR / TILESIZE;
446   int ffx, ffy;
447
448   // fx += dx * TILESIZE_VAR / TILESIZE;
449   // fy += dy * TILESIZE_VAR / TILESIZE;
450 #else
451   fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
452   fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
453 #endif
454
455   ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
456   ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
457
458   if (EVEN(SCR_FIELDX))
459   {
460     if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
461       fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
462     else
463       fx += (dx_var > 0 ? TILEX_VAR : 0);
464   }
465   else
466   {
467     fx += dx_var;
468   }
469
470   if (EVEN(SCR_FIELDY))
471   {
472     if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
473       fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
474     else
475       fy += (dy_var > 0 ? TILEY_VAR : 0);
476   }
477   else
478   {
479     fy += dy_var;
480   }
481
482 #if 0
483   printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
484          scroll_x, scroll_y,
485          SBX_Left, SBX_Right,
486          SBY_Upper, SBY_Lower,
487          fx, fy);
488 #endif
489
490   if (border.draw_masked[GAME_MODE_PLAYING])
491   {
492     if (buffer != backbuffer)
493     {
494       /* copy playfield buffer to backbuffer to add masked border */
495       BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
496       DrawMaskedBorder(REDRAW_FIELD);
497     }
498
499     BlitBitmap(backbuffer, target_bitmap,
500                REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
501                REAL_SX, REAL_SY);
502   }
503   else
504   {
505     BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
506   }
507 }
508
509 void BackToFront()
510 {
511   int x, y;
512   DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
513
514 #if 0
515   printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
516   for (x = 0; x < SCR_FIELDX; x++)
517     for (y = 0 ; y < SCR_FIELDY; y++)
518       if (redraw[redraw_x1 + x][redraw_y1 + y])
519         printf("::: - %d, %d [%s]\n",
520                LEVELX(x), LEVELY(y),
521                EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
522 #endif
523
524   if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
525     redraw_mask |= REDRAW_FIELD;
526
527 #if 0
528   // never redraw single tiles, always redraw the whole field
529   // (redrawing single tiles up to a certain threshold was faster on old,
530   // now legacy graphics, but slows things down on modern graphics now)
531   // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
532   if (redraw_mask & REDRAW_TILES)
533     redraw_mask |= REDRAW_FIELD;
534 #endif
535
536 #if 0
537   /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
538   /* (force full redraw) */
539   if (game_status == GAME_MODE_PLAYING)
540     redraw_mask |= REDRAW_FIELD;
541 #endif
542
543   if (redraw_mask & REDRAW_FIELD)
544     redraw_mask &= ~REDRAW_TILES;
545
546   if (redraw_mask == REDRAW_NONE)
547     return;
548
549 #if 0
550   printf("::: ");
551   if (redraw_mask & REDRAW_ALL)
552     printf("[REDRAW_ALL]");
553   if (redraw_mask & REDRAW_FIELD)
554     printf("[REDRAW_FIELD]");
555   if (redraw_mask & REDRAW_TILES)
556     printf("[REDRAW_TILES]");
557   if (redraw_mask & REDRAW_DOOR_1)
558     printf("[REDRAW_DOOR_1]");
559   if (redraw_mask & REDRAW_DOOR_2)
560     printf("[REDRAW_DOOR_2]");
561   if (redraw_mask & REDRAW_FROM_BACKBUFFER)
562     printf("[REDRAW_FROM_BACKBUFFER]");
563   printf(" [%d]\n", FrameCounter);
564 #endif
565
566   if (redraw_mask & REDRAW_TILES &&
567       game_status == GAME_MODE_PLAYING &&
568       border.draw_masked[GAME_MODE_PLAYING])
569     redraw_mask |= REDRAW_FIELD;
570
571   if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
572   {
573     static boolean last_frame_skipped = FALSE;
574     boolean skip_even_when_not_scrolling = TRUE;
575     boolean just_scrolling = (ScreenMovDir != 0);
576     boolean verbose = FALSE;
577
578     if (global.fps_slowdown_factor > 1 &&
579         (FrameCounter % global.fps_slowdown_factor) &&
580         (just_scrolling || skip_even_when_not_scrolling))
581     {
582       redraw_mask &= ~REDRAW_MAIN;
583
584       last_frame_skipped = TRUE;
585
586       if (verbose)
587         printf("FRAME SKIPPED\n");
588     }
589     else
590     {
591       if (last_frame_skipped)
592         redraw_mask |= REDRAW_FIELD;
593
594       last_frame_skipped = FALSE;
595
596       if (verbose)
597         printf("frame not skipped\n");
598     }
599   }
600
601   /* synchronize X11 graphics at this point; if we would synchronize the
602      display immediately after the buffer switching (after the XFlush),
603      this could mean that we have to wait for the graphics to complete,
604      although we could go on doing calculations for the next frame */
605
606   SyncDisplay();
607
608   /* never draw masked border to backbuffer when using playfield buffer */
609   if (game_status != GAME_MODE_PLAYING ||
610       redraw_mask & REDRAW_FROM_BACKBUFFER ||
611       buffer == backbuffer)
612     DrawMaskedBorder(redraw_mask);
613   else
614     DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
615
616   if (redraw_mask & REDRAW_ALL)
617   {
618     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
619
620     redraw_mask = REDRAW_NONE;
621   }
622
623   if (redraw_mask & REDRAW_FIELD)
624   {
625 #if 0
626     printf("::: REDRAW_FIELD\n");
627 #endif
628
629     if (game_status != GAME_MODE_PLAYING ||
630         redraw_mask & REDRAW_FROM_BACKBUFFER)
631     {
632       BlitBitmap(backbuffer, window,
633                  REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
634     }
635     else
636     {
637 #if 1
638       BlitScreenToBitmap(window);
639 #else
640       int fx = FX, fy = FY;
641
642 #if NEW_TILESIZE
643       int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
644       int dy = (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
645       int dx_var = dx * TILESIZE_VAR / TILESIZE;
646       int dy_var = dy * TILESIZE_VAR / TILESIZE;
647       int ffx, ffy;
648
649       // fx += dx * TILESIZE_VAR / TILESIZE;
650       // fy += dy * TILESIZE_VAR / TILESIZE;
651 #else
652       fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
653       fy += (ScreenMovDir & (MV_UP | MV_DOWN)    ? ScreenGfxPos : 0);
654 #endif
655
656       /* !!! THIS WORKS !!! */
657
658       printf("::: %d, %d\n", scroll_x, scroll_y);
659
660       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
661       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
662
663       if (EVEN(SCR_FIELDX))
664       {
665         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
666           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
667         else
668           fx += (dx > 0 ? TILEX_VAR : 0);
669       }
670       else
671       {
672         fx += dx;
673       }
674
675       if (EVEN(SCR_FIELDY))
676       {
677         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
678           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
679         else
680           fy += (dy > 0 ? TILEY_VAR : 0);
681       }
682       else
683       {
684         fy += dy;
685       }
686
687       if (border.draw_masked[GAME_MODE_PLAYING])
688       {
689         if (buffer != backbuffer)
690         {
691           /* copy playfield buffer to backbuffer to add masked border */
692           BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
693           DrawMaskedBorder(REDRAW_FIELD);
694         }
695
696         BlitBitmap(backbuffer, window,
697                    REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
698                    REAL_SX, REAL_SY);
699       }
700       else
701       {
702         BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
703       }
704 #endif
705
706 #if 0
707 #ifdef DEBUG
708       printf("redrawing all (ScreenGfxPos == %d) because %s\n",
709              ScreenGfxPos,
710              (setup.soft_scrolling ?
711               "setup.soft_scrolling" :
712               ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
713               "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
714               ABS(ScreenGfxPos) == ScrollStepSize ?
715               "ABS(ScreenGfxPos) == ScrollStepSize" :
716               "redraw_tiles > REDRAWTILES_THRESHOLD"));
717 #endif
718 #endif
719     }
720
721     redraw_mask &= ~REDRAW_MAIN;
722   }
723
724   if (redraw_mask & REDRAW_DOORS)
725   {
726     if (redraw_mask & REDRAW_DOOR_1)
727       BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
728
729     if (redraw_mask & REDRAW_DOOR_2)
730       BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
731
732     if (redraw_mask & REDRAW_DOOR_3)
733       BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
734
735     redraw_mask &= ~REDRAW_DOORS;
736   }
737
738   if (redraw_mask & REDRAW_MICROLEVEL)
739   {
740     BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
741                SX, SY + 10 * TILEY);
742
743     redraw_mask &= ~REDRAW_MICROLEVEL;
744   }
745
746   if (redraw_mask & REDRAW_TILES)
747   {
748 #if 0
749     printf("::: REDRAW_TILES\n");
750 #endif
751
752 #if NEW_TILESIZE
753
754 #if 1
755     InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
756
757     {
758       int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
759       int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
760
761       int dx = 0, dy = 0;
762       int dx_var = dx * TILESIZE_VAR / TILESIZE;
763       int dy_var = dy * TILESIZE_VAR / TILESIZE;
764       int ffx, ffy;
765       int fx = FX, fy = FY;
766
767       int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
768       int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
769
770       ffx = (scroll_x - SBX_Left)  * TILEX_VAR + dx_var;
771       ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
772
773       if (EVEN(SCR_FIELDX))
774       {
775         if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
776         {
777           fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
778
779           if (fx % TILEX_VAR)
780             sx -= TILEX_VAR / 2;
781           else
782             sx -= TILEX_VAR;
783         }
784         else
785         {
786           fx += (dx_var > 0 ? TILEX_VAR : 0);
787         }
788       }
789
790       if (EVEN(SCR_FIELDY))
791       {
792         if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
793         {
794           fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
795
796           if (fy % TILEY_VAR)
797             sy -= TILEY_VAR / 2;
798           else
799             sy -= TILEY_VAR;
800         }
801         else
802         {
803           fy += (dy_var > 0 ? TILEY_VAR : 0);
804         }
805       }
806
807 #if 0
808       printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
809 #endif
810
811       for (x = 0; x < scr_fieldx; x++)
812         for (y = 0 ; y < scr_fieldy; y++)
813           if (redraw[redraw_x1 + x][redraw_y1 + y])
814             BlitBitmap(buffer, window,
815                        FX + x * TILEX_VAR, FY + y * TILEY_VAR,
816                        TILEX_VAR, TILEY_VAR,
817                        sx + x * TILEX_VAR, sy + y * TILEY_VAR);
818     }
819
820     InitGfxClipRegion(FALSE, -1, -1, -1, -1);
821 #else
822     for (x = 0; x < SCR_FIELDX; x++)
823       for (y = 0 ; y < SCR_FIELDY; y++)
824         if (redraw[redraw_x1 + x][redraw_y1 + y])
825           BlitBitmap(buffer, window,
826                      FX + x * TILEX_VAR, FY + y * TILEY_VAR,
827                      TILEX_VAR, TILEY_VAR,
828                      SX + x * TILEX_VAR, SY + y * TILEY_VAR);
829 #endif
830
831 #else
832     for (x = 0; x < SCR_FIELDX; x++)
833       for (y = 0 ; y < SCR_FIELDY; y++)
834         if (redraw[redraw_x1 + x][redraw_y1 + y])
835           BlitBitmap(buffer, window,
836                      FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
837                      SX + x * TILEX, SY + y * TILEY);
838 #endif
839   }
840
841   if (redraw_mask & REDRAW_FPS)         /* display frames per second */
842   {
843     char text[100];
844     char info1[100];
845
846     sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
847     if (!global.fps_slowdown)
848       info1[0] = '\0';
849
850     sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
851 #if 1
852     DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
853 #else
854     DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
855 #endif
856   }
857
858   FlushDisplay();
859
860   for (x = 0; x < MAX_BUF_XSIZE; x++)
861     for (y = 0; y < MAX_BUF_YSIZE; y++)
862       redraw[x][y] = 0;
863   redraw_tiles = 0;
864   redraw_mask = REDRAW_NONE;
865 }
866
867 static void FadeCrossSaveBackbuffer()
868 {
869   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
870 }
871
872 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
873 {
874   static int fade_type_skip = FADE_TYPE_NONE;
875   void (*draw_border_function)(void) = NULL;
876   Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
877   int x, y, width, height;
878   int fade_delay, post_delay;
879
880   if (fade_type == FADE_TYPE_FADE_OUT)
881   {
882     if (fade_type_skip != FADE_TYPE_NONE)
883     {
884 #if 0
885       printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
886 #endif
887
888       /* skip all fade operations until specified fade operation */
889       if (fade_type & fade_type_skip)
890         fade_type_skip = FADE_TYPE_NONE;
891
892       return;
893     }
894
895     if (fading.fade_mode & FADE_TYPE_TRANSFORM)
896     {
897       FadeCrossSaveBackbuffer();
898
899       return;
900     }
901   }
902
903   redraw_mask |= fade_mask;
904
905   if (fade_type == FADE_TYPE_SKIP)
906   {
907 #if 0
908     printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
909 #endif
910
911     fade_type_skip = fade_mode;
912
913     return;
914   }
915
916 #if 0
917   printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
918          fade_type_skip);
919 #endif
920
921 #if 1
922   fade_delay = fading.fade_delay;
923   post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
924 #endif
925
926   if (fade_type_skip != FADE_TYPE_NONE)
927   {
928 #if 0
929     printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
930 #endif
931
932     /* skip all fade operations until specified fade operation */
933     if (fade_type & fade_type_skip)
934       fade_type_skip = FADE_TYPE_NONE;
935
936 #if 1
937     fade_delay = 0;
938 #else
939     return;
940 #endif
941   }
942
943 #if 1
944   if (global.autoplay_leveldir)
945   {
946     // fading.fade_mode = FADE_MODE_NONE;
947
948     return;
949   }
950 #endif
951
952 #if 0
953   if (fading.fade_mode == FADE_MODE_NONE)
954   {
955     BackToFront();
956
957     return;
958   }
959 #endif
960
961   /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
962
963 #if 0
964   printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
965 #endif
966
967 #if 0
968   if (fade_mask == REDRAW_NONE)
969     fade_mask = REDRAW_FIELD;
970 #endif
971
972   // if (fade_mask & REDRAW_FIELD)
973   if (fade_mask == REDRAW_FIELD)
974   {
975     x = REAL_SX;
976     y = REAL_SY;
977     width  = FULL_SXSIZE;
978     height = FULL_SYSIZE;
979
980 #if 0
981     fade_delay = fading.fade_delay;
982     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
983 #endif
984
985     if (border.draw_masked_when_fading)
986       draw_border_function = DrawMaskedBorder_FIELD;    /* update when fading */
987     else
988       DrawMaskedBorder_FIELD();                         /* draw once */
989   }
990   else          /* REDRAW_ALL */
991   {
992     x = 0;
993     y = 0;
994     width  = WIN_XSIZE;
995     height = WIN_YSIZE;
996
997 #if 0
998     fade_delay = fading.fade_delay;
999     post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
1000 #endif
1001   }
1002
1003 #if 1
1004   if (!setup.fade_screens ||
1005       fade_delay == 0 ||
1006       fading.fade_mode == FADE_MODE_NONE)
1007 #else
1008   if (!setup.fade_screens || fade_delay == 0)
1009 #endif
1010   {
1011     if (fade_mode == FADE_MODE_FADE_OUT)
1012       return;
1013
1014 #if 0
1015     if (fade_mode == FADE_MODE_FADE_OUT &&
1016         fading.fade_mode != FADE_MODE_NONE)
1017       ClearRectangle(backbuffer, x, y, width, height);
1018 #endif
1019
1020 #if 1
1021     BlitBitmap(backbuffer, window, x, y, width, height, x, y);
1022     redraw_mask = REDRAW_NONE;
1023 #else
1024     BackToFront();
1025 #endif
1026
1027     return;
1028   }
1029
1030   FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
1031                 draw_border_function);
1032
1033   redraw_mask &= ~fade_mask;
1034 }
1035
1036 void FadeIn(int fade_mask)
1037 {
1038   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1039     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
1040   else
1041     FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
1042 }
1043
1044 void FadeOut(int fade_mask)
1045 {
1046   if (fading.fade_mode & FADE_TYPE_TRANSFORM)
1047     FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
1048   else
1049     FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
1050
1051   global.border_status = game_status;
1052 }
1053
1054 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
1055 {
1056   static struct TitleFadingInfo fading_leave_stored;
1057
1058   if (set)
1059     fading_leave_stored = fading_leave;
1060   else
1061     fading = fading_leave_stored;
1062 }
1063
1064 void FadeSetEnterMenu()
1065 {
1066   fading = menu.enter_menu;
1067
1068 #if 0
1069   printf("::: storing enter_menu\n");
1070 #endif
1071
1072   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1073 }
1074
1075 void FadeSetLeaveMenu()
1076 {
1077   fading = menu.leave_menu;
1078
1079 #if 0
1080   printf("::: storing leave_menu\n");
1081 #endif
1082
1083   FadeSetLeaveNext(fading, TRUE);       /* (keep same fade mode) */
1084 }
1085
1086 void FadeSetEnterScreen()
1087 {
1088   fading = menu.enter_screen[game_status];
1089
1090 #if 0
1091   printf("::: storing leave_screen[%d]\n", game_status);
1092 #endif
1093
1094   FadeSetLeaveNext(menu.leave_screen[game_status], TRUE);       /* store */
1095 }
1096
1097 void FadeSetNextScreen()
1098 {
1099   fading = menu.next_screen;
1100
1101 #if 0
1102   printf("::: storing next_screen\n");
1103 #endif
1104
1105   // (do not overwrite fade mode set by FadeSetEnterScreen)
1106   // FadeSetLeaveNext(fading, TRUE);    /* (keep same fade mode) */
1107 }
1108
1109 void FadeSetLeaveScreen()
1110 {
1111 #if 0
1112   printf("::: recalling last stored value\n");
1113 #endif
1114
1115   FadeSetLeaveNext(menu.leave_screen[game_status], FALSE);      /* recall */
1116 }
1117
1118 void FadeSetFromType(int type)
1119 {
1120   if (type & TYPE_ENTER_SCREEN)
1121     FadeSetEnterScreen();
1122   else if (type & TYPE_ENTER)
1123     FadeSetEnterMenu();
1124   else if (type & TYPE_LEAVE)
1125     FadeSetLeaveMenu();
1126 }
1127
1128 void FadeSetDisabled()
1129 {
1130   static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1131
1132   fading = fading_none;
1133 }
1134
1135 void FadeSkipNextFadeIn()
1136 {
1137   FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1138 }
1139
1140 void FadeSkipNextFadeOut()
1141 {
1142   FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1143 }
1144
1145 void SetWindowBackgroundImageIfDefined(int graphic)
1146 {
1147   if (graphic_info[graphic].bitmap)
1148     SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1149 }
1150
1151 void SetMainBackgroundImageIfDefined(int graphic)
1152 {
1153   if (graphic_info[graphic].bitmap)
1154     SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1155 }
1156
1157 void SetDoorBackgroundImageIfDefined(int graphic)
1158 {
1159   if (graphic_info[graphic].bitmap)
1160     SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1161 }
1162
1163 void SetWindowBackgroundImage(int graphic)
1164 {
1165   SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1166                             graphic_info[graphic].bitmap ?
1167                             graphic_info[graphic].bitmap :
1168                             graphic_info[IMG_BACKGROUND].bitmap);
1169 }
1170
1171 void SetMainBackgroundImage(int graphic)
1172 {
1173   SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1174                           graphic_info[graphic].bitmap ?
1175                           graphic_info[graphic].bitmap :
1176                           graphic_info[IMG_BACKGROUND].bitmap);
1177 }
1178
1179 void SetDoorBackgroundImage(int graphic)
1180 {
1181   SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1182                           graphic_info[graphic].bitmap ?
1183                           graphic_info[graphic].bitmap :
1184                           graphic_info[IMG_BACKGROUND].bitmap);
1185 }
1186
1187 void SetPanelBackground()
1188 {
1189 #if 1
1190   struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1191
1192 #if 1
1193   BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1194                   gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1195 #else
1196   /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1197   ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1198   BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1199              MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1200 #endif
1201 #else
1202   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1203              DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1204 #endif
1205
1206   SetDoorBackgroundBitmap(bitmap_db_panel);
1207 }
1208
1209 void DrawBackground(int x, int y, int width, int height)
1210 {
1211   /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1212   /* (when entering hall of fame after playing) */
1213 #if 0
1214   ClearRectangleOnBackground(drawto, x, y, width, height);
1215 #else
1216   ClearRectangleOnBackground(backbuffer, x, y, width, height);
1217 #endif
1218
1219 #if 1
1220
1221 #if 1
1222   if (IN_GFX_FIELD_FULL(x, y))
1223     redraw_mask |= REDRAW_FIELD;
1224   else if (IN_GFX_DOOR_1(x, y))
1225     redraw_mask |= REDRAW_DOOR_1;
1226   else if (IN_GFX_DOOR_2(x, y))
1227     redraw_mask |= REDRAW_DOOR_2;
1228   else if (IN_GFX_DOOR_3(x, y))
1229     redraw_mask |= REDRAW_DOOR_3;
1230 #else
1231   /* (this only works for the current arrangement of playfield and panels) */
1232   if (x < gfx.dx)
1233     redraw_mask |= REDRAW_FIELD;
1234   else if (y < gfx.vy)
1235     redraw_mask |= REDRAW_DOOR_1;
1236   else
1237     redraw_mask |= REDRAW_DOOR_2;
1238 #endif
1239
1240 #else
1241   /* (this is just wrong (when drawing to one of the two door panel areas)) */
1242   redraw_mask |= REDRAW_FIELD;
1243 #endif
1244 }
1245
1246 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1247 {
1248   struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1249
1250   if (font->bitmap == NULL)
1251     return;
1252
1253   DrawBackground(x, y, width, height);
1254 }
1255
1256 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1257 {
1258   struct GraphicInfo *g = &graphic_info[graphic];
1259
1260   if (g->bitmap == NULL)
1261     return;
1262
1263   DrawBackground(x, y, width, height);
1264 }
1265
1266 void ClearField()
1267 {
1268   /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1269   /* (when entering hall of fame after playing) */
1270   DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1271
1272   /* !!! maybe this should be done before clearing the background !!! */
1273   if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1274   {
1275     ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1276     SetDrawtoField(DRAW_BUFFERED);
1277   }
1278   else
1279     SetDrawtoField(DRAW_BACKBUFFER);
1280 }
1281
1282 void MarkTileDirty(int x, int y)
1283 {
1284   int xx = redraw_x1 + x;
1285   int yy = redraw_y1 + y;
1286
1287   if (!redraw[xx][yy])
1288     redraw_tiles++;
1289
1290   redraw[xx][yy] = TRUE;
1291   redraw_mask |= REDRAW_TILES;
1292 }
1293
1294 void SetBorderElement()
1295 {
1296   int x, y;
1297
1298   BorderElement = EL_EMPTY;
1299
1300   for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1301   {
1302     for (x = 0; x < lev_fieldx; x++)
1303     {
1304       if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1305         BorderElement = EL_STEELWALL;
1306
1307       if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1308         x = lev_fieldx - 2;
1309     }
1310   }
1311 }
1312
1313 void FloodFillLevel(int from_x, int from_y, int fill_element,
1314                     short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1315                     int max_fieldx, int max_fieldy)
1316 {
1317   int i,x,y;
1318   int old_element;
1319   static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1320   static int safety = 0;
1321
1322   /* check if starting field still has the desired content */
1323   if (field[from_x][from_y] == fill_element)
1324     return;
1325
1326   safety++;
1327
1328   if (safety > max_fieldx * max_fieldy)
1329     Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1330
1331   old_element = field[from_x][from_y];
1332   field[from_x][from_y] = fill_element;
1333
1334   for (i = 0; i < 4; i++)
1335   {
1336     x = from_x + check[i][0];
1337     y = from_y + check[i][1];
1338
1339     if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1340       FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1341   }
1342
1343   safety--;
1344 }
1345
1346 void SetRandomAnimationValue(int x, int y)
1347 {
1348   gfx.anim_random_frame = GfxRandom[x][y];
1349 }
1350
1351 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1352 {
1353   /* animation synchronized with global frame counter, not move position */
1354   if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1355     sync_frame = FrameCounter;
1356
1357   return getAnimationFrame(graphic_info[graphic].anim_frames,
1358                            graphic_info[graphic].anim_delay,
1359                            graphic_info[graphic].anim_mode,
1360                            graphic_info[graphic].anim_start_frame,
1361                            sync_frame);
1362 }
1363
1364 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1365                               Bitmap **bitmap, int *x, int *y,
1366                               boolean get_backside)
1367 {
1368   struct
1369   {
1370     int width_mult, width_div;
1371     int height_mult, height_div;
1372   }
1373   offset_calc[6] =
1374   {
1375     { 15, 16,   2, 3    },      /* 1 x 1 */
1376     { 7, 8,     2, 3    },      /* 2 x 2 */
1377     { 3, 4,     2, 3    },      /* 4 x 4 */
1378     { 1, 2,     2, 3    },      /* 8 x 8 */
1379     { 0, 1,     2, 3    },      /* 16 x 16 */
1380     { 0, 1,     0, 1    },      /* 32 x 32 */
1381   };
1382   struct GraphicInfo *g = &graphic_info[graphic];
1383   Bitmap *src_bitmap = g->bitmap;
1384   int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1385   int offset_calc_pos = log_2(tilesize);
1386   int width_mult  = offset_calc[offset_calc_pos].width_mult;
1387   int width_div   = offset_calc[offset_calc_pos].width_div;
1388   int height_mult = offset_calc[offset_calc_pos].height_mult;
1389   int height_div  = offset_calc[offset_calc_pos].height_div;
1390   int startx = src_bitmap->width * width_mult / width_div;
1391   int starty = src_bitmap->height * height_mult / height_div;
1392 #if NEW_TILESIZE
1393   int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1394     tilesize / TILESIZE;
1395   int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1396     tilesize / TILESIZE;
1397 #else
1398   int src_x = g->src_x * tilesize / TILESIZE;
1399   int src_y = g->src_y * tilesize / TILESIZE;
1400 #endif
1401   int width = g->width * tilesize / TILESIZE;
1402   int height = g->height * tilesize / TILESIZE;
1403   int offset_x = g->offset_x * tilesize / TILESIZE;
1404   int offset_y = g->offset_y * tilesize / TILESIZE;
1405
1406   if (g->offset_y == 0)         /* frames are ordered horizontally */
1407   {
1408     int max_width = g->anim_frames_per_line * width;
1409     int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1410
1411     src_x = pos % max_width;
1412     src_y = src_y % height + pos / max_width * height;
1413   }
1414   else if (g->offset_x == 0)    /* frames are ordered vertically */
1415   {
1416     int max_height = g->anim_frames_per_line * height;
1417     int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1418
1419     src_x = src_x % width + pos / max_height * width;
1420     src_y = pos % max_height;
1421   }
1422   else                          /* frames are ordered diagonally */
1423   {
1424     src_x = src_x + frame * offset_x;
1425     src_y = src_y + frame * offset_y;
1426   }
1427
1428   *bitmap = src_bitmap;
1429   *x = startx + src_x;
1430   *y = starty + src_y;
1431 }
1432
1433 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1434                               int *x, int *y, boolean get_backside)
1435 {
1436   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1437                            get_backside);
1438 }
1439
1440 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1441                            Bitmap **bitmap, int *x, int *y)
1442 {
1443   getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1444 }
1445
1446 void getFixedGraphicSource(int graphic, int frame,
1447                            Bitmap **bitmap, int *x, int *y)
1448 {
1449   getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1450 }
1451
1452 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1453 {
1454 #if 1
1455   getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1456 #else
1457   struct GraphicInfo *g = &graphic_info[graphic];
1458   int mini_startx = 0;
1459   int mini_starty = g->bitmap->height * 2 / 3;
1460
1461   *bitmap = g->bitmap;
1462   *x = mini_startx + g->src_x / 2;
1463   *y = mini_starty + g->src_y / 2;
1464 #endif
1465 }
1466
1467 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1468                                 int *x, int *y, boolean get_backside)
1469 {
1470   struct GraphicInfo *g = &graphic_info[graphic];
1471   int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1472   int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1473
1474 #if NEW_TILESIZE
1475   if (TILESIZE_VAR != TILESIZE)
1476     return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1477                                     get_backside);
1478 #endif
1479
1480   *bitmap = g->bitmap;
1481
1482   if (g->offset_y == 0)         /* frames are ordered horizontally */
1483   {
1484     int max_width = g->anim_frames_per_line * g->width;
1485     int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1486
1487     *x = pos % max_width;
1488     *y = src_y % g->height + pos / max_width * g->height;
1489   }
1490   else if (g->offset_x == 0)    /* frames are ordered vertically */
1491   {
1492     int max_height = g->anim_frames_per_line * g->height;
1493     int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1494
1495     *x = src_x % g->width + pos / max_height * g->width;
1496     *y = pos % max_height;
1497   }
1498   else                          /* frames are ordered diagonally */
1499   {
1500     *x = src_x + frame * g->offset_x;
1501     *y = src_y + frame * g->offset_y;
1502   }
1503 }
1504
1505 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1506 {
1507   getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1508 }
1509
1510 void DrawGraphic(int x, int y, int graphic, int frame)
1511 {
1512 #if DEBUG
1513   if (!IN_SCR_FIELD(x, y))
1514   {
1515     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1516     printf("DrawGraphic(): This should never happen!\n");
1517     return;
1518   }
1519 #endif
1520
1521 #if NEW_TILESIZE
1522   DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1523                  frame);
1524 #else
1525   DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1526 #endif
1527   MarkTileDirty(x, y);
1528 }
1529
1530 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1531 {
1532 #if DEBUG
1533   if (!IN_SCR_FIELD(x, y))
1534   {
1535     printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1536     printf("DrawGraphic(): This should never happen!\n");
1537     return;
1538   }
1539 #endif
1540
1541   DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1542                       frame);
1543   MarkTileDirty(x, y);
1544 }
1545
1546 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1547                     int frame)
1548 {
1549   Bitmap *src_bitmap;
1550   int src_x, src_y;
1551
1552   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1553 #if NEW_TILESIZE
1554   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1555 #else
1556   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1557 #endif
1558 }
1559
1560 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1561                          int frame)
1562 {
1563   Bitmap *src_bitmap;
1564   int src_x, src_y;
1565
1566   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1567   BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1568 }
1569
1570 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1571 {
1572 #if DEBUG
1573   if (!IN_SCR_FIELD(x, y))
1574   {
1575     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1576     printf("DrawGraphicThruMask(): This should never happen!\n");
1577     return;
1578   }
1579 #endif
1580
1581 #if NEW_TILESIZE
1582   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1583                          graphic, frame);
1584 #else
1585   DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1586                          frame);
1587 #endif
1588   MarkTileDirty(x, y);
1589 }
1590
1591 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1592 {
1593 #if DEBUG
1594   if (!IN_SCR_FIELD(x, y))
1595   {
1596     printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1597     printf("DrawGraphicThruMask(): This should never happen!\n");
1598     return;
1599   }
1600 #endif
1601
1602   DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1603                               graphic, frame);
1604   MarkTileDirty(x, y);
1605 }
1606
1607 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1608                             int frame)
1609 {
1610   Bitmap *src_bitmap;
1611   int src_x, src_y;
1612
1613   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1614
1615   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1616                 dst_x - src_x, dst_y - src_y);
1617 #if NEW_TILESIZE
1618   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1619                    dst_x, dst_y);
1620 #else
1621   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1622 #endif
1623 }
1624
1625 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1626                                  int graphic, int frame)
1627 {
1628   Bitmap *src_bitmap;
1629   int src_x, src_y;
1630
1631   getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1632
1633   SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1634                 dst_x - src_x, dst_y - src_y);
1635   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1636 }
1637
1638 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1639 {
1640   DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1641                       frame, tilesize);
1642   MarkTileDirty(x / tilesize, y / tilesize);
1643 }
1644
1645 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1646                          int tilesize)
1647 {
1648   Bitmap *src_bitmap;
1649   int src_x, src_y;
1650
1651   getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1652   BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1653 }
1654
1655 void DrawMiniGraphic(int x, int y, int graphic)
1656 {
1657   DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1658   MarkTileDirty(x / 2, y / 2);
1659 }
1660
1661 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1662 {
1663   Bitmap *src_bitmap;
1664   int src_x, src_y;
1665
1666   getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1667   BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1668 }
1669
1670 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1671                                             int graphic, int frame,
1672                                             int cut_mode, int mask_mode)
1673 {
1674   Bitmap *src_bitmap;
1675   int src_x, src_y;
1676   int dst_x, dst_y;
1677   int width = TILEX, height = TILEY;
1678   int cx = 0, cy = 0;
1679
1680   if (dx || dy)                 /* shifted graphic */
1681   {
1682     if (x < BX1)                /* object enters playfield from the left */
1683     {
1684       x = BX1;
1685       width = dx;
1686       cx = TILEX - dx;
1687       dx = 0;
1688     }
1689     else if (x > BX2)           /* object enters playfield from the right */
1690     {
1691       x = BX2;
1692       width = -dx;
1693       dx = TILEX + dx;
1694     }
1695     else if (x==BX1 && dx < 0)  /* object leaves playfield to the left */
1696     {
1697       width += dx;
1698       cx = -dx;
1699       dx = 0;
1700     }
1701     else if (x==BX2 && dx > 0)  /* object leaves playfield to the right */
1702       width -= dx;
1703     else if (dx)                /* general horizontal movement */
1704       MarkTileDirty(x + SIGN(dx), y);
1705
1706     if (y < BY1)                /* object enters playfield from the top */
1707     {
1708       if (cut_mode==CUT_BELOW)  /* object completely above top border */
1709         return;
1710
1711       y = BY1;
1712       height = dy;
1713       cy = TILEY - dy;
1714       dy = 0;
1715     }
1716     else if (y > BY2)           /* object enters playfield from the bottom */
1717     {
1718       y = BY2;
1719       height = -dy;
1720       dy = TILEY + dy;
1721     }
1722     else if (y==BY1 && dy < 0)  /* object leaves playfield to the top */
1723     {
1724       height += dy;
1725       cy = -dy;
1726       dy = 0;
1727     }
1728     else if (dy > 0 && cut_mode == CUT_ABOVE)
1729     {
1730       if (y == BY2)             /* object completely above bottom border */
1731         return;
1732
1733       height = dy;
1734       cy = TILEY - dy;
1735       dy = TILEY;
1736       MarkTileDirty(x, y + 1);
1737     }                           /* object leaves playfield to the bottom */
1738     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1739       height -= dy;
1740     else if (dy)                /* general vertical movement */
1741       MarkTileDirty(x, y + SIGN(dy));
1742   }
1743
1744 #if DEBUG
1745   if (!IN_SCR_FIELD(x, y))
1746   {
1747     printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1748     printf("DrawGraphicShifted(): This should never happen!\n");
1749     return;
1750   }
1751 #endif
1752
1753 #if NEW_TILESIZE
1754   width = width * TILESIZE_VAR / TILESIZE;
1755   height = height * TILESIZE_VAR / TILESIZE;
1756   cx = cx * TILESIZE_VAR / TILESIZE;
1757   cy = cy * TILESIZE_VAR / TILESIZE;
1758   dx = dx * TILESIZE_VAR / TILESIZE;
1759   dy = dy * TILESIZE_VAR / TILESIZE;
1760 #endif
1761
1762   if (width > 0 && height > 0)
1763   {
1764     getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1765
1766     src_x += cx;
1767     src_y += cy;
1768
1769 #if NEW_TILESIZE
1770     dst_x = FX + x * TILEX_VAR + dx;
1771     dst_y = FY + y * TILEY_VAR + dy;
1772 #else
1773     dst_x = FX + x * TILEX + dx;
1774     dst_y = FY + y * TILEY + dy;
1775 #endif
1776
1777     if (mask_mode == USE_MASKING)
1778     {
1779       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1780                     dst_x - src_x, dst_y - src_y);
1781       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1782                        dst_x, dst_y);
1783     }
1784     else
1785       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1786                  dst_x, dst_y);
1787
1788     MarkTileDirty(x, y);
1789   }
1790 }
1791
1792 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1793                                             int graphic, int frame,
1794                                             int cut_mode, int mask_mode)
1795 {
1796   Bitmap *src_bitmap;
1797   int src_x, src_y;
1798   int dst_x, dst_y;
1799 #if NEW_TILESIZE
1800   int width = TILEX_VAR, height = TILEY_VAR;
1801 #else
1802   int width = TILEX, height = TILEY;
1803 #endif
1804   int x1 = x;
1805   int y1 = y;
1806   int x2 = x + SIGN(dx);
1807   int y2 = y + SIGN(dy);
1808 #if 0
1809   /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1810   int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1811 #else
1812   /* movement with two-tile animations must be sync'ed with movement position,
1813      not with current GfxFrame (which can be higher when using slow movement) */
1814   int anim_pos = (dx ? ABS(dx) : ABS(dy));
1815   int anim_frames = graphic_info[graphic].anim_frames;
1816 #if 1
1817   /* (we also need anim_delay here for movement animations with less frames) */
1818   int anim_delay = graphic_info[graphic].anim_delay;
1819   int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1820 #else
1821   int sync_frame = anim_pos * anim_frames / TILESIZE;
1822 #endif
1823 #endif
1824   boolean draw_start_tile = (cut_mode != CUT_ABOVE);    /* only for falling! */
1825   boolean draw_end_tile   = (cut_mode != CUT_BELOW);    /* only for falling! */
1826
1827   /* re-calculate animation frame for two-tile movement animation */
1828   frame = getGraphicAnimationFrame(graphic, sync_frame);
1829
1830 #if 0
1831 #if 0
1832   printf("::: %d, %d, %d => %d [%d]\n",
1833          anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1834 #else
1835   printf("::: %d, %d => %d\n",
1836          anim_pos, anim_frames, sync_frame);
1837 #endif
1838 #endif
1839
1840 #if 0
1841   printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1842          GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1843 #endif
1844
1845   /* check if movement start graphic inside screen area and should be drawn */
1846   if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1847   {
1848     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1849
1850 #if NEW_TILESIZE
1851     dst_x = FX + x1 * TILEX_VAR;
1852     dst_y = FY + y1 * TILEY_VAR;
1853 #else
1854     dst_x = FX + x1 * TILEX;
1855     dst_y = FY + y1 * TILEY;
1856 #endif
1857
1858     if (mask_mode == USE_MASKING)
1859     {
1860       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1861                     dst_x - src_x, dst_y - src_y);
1862       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1863                        dst_x, dst_y);
1864     }
1865     else
1866       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1867                  dst_x, dst_y);
1868
1869     MarkTileDirty(x1, y1);
1870   }
1871
1872   /* check if movement end graphic inside screen area and should be drawn */
1873   if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1874   {
1875     getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1876
1877 #if NEW_TILESIZE
1878     dst_x = FX + x2 * TILEX_VAR;
1879     dst_y = FY + y2 * TILEY_VAR;
1880 #else
1881     dst_x = FX + x2 * TILEX;
1882     dst_y = FY + y2 * TILEY;
1883 #endif
1884
1885     if (mask_mode == USE_MASKING)
1886     {
1887       SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1888                     dst_x - src_x, dst_y - src_y);
1889       BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1890                        dst_x, dst_y);
1891     }
1892     else
1893       BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1894                  dst_x, dst_y);
1895
1896     MarkTileDirty(x2, y2);
1897   }
1898 }
1899
1900 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1901                                int graphic, int frame,
1902                                int cut_mode, int mask_mode)
1903 {
1904   if (graphic < 0)
1905   {
1906     DrawGraphic(x, y, graphic, frame);
1907
1908     return;
1909   }
1910
1911   if (graphic_info[graphic].double_movement)    /* EM style movement images */
1912     DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1913   else
1914     DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1915 }
1916
1917 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1918                                 int frame, int cut_mode)
1919 {
1920   DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1921 }
1922
1923 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1924                           int cut_mode, int mask_mode)
1925 {
1926   int lx = LEVELX(x), ly = LEVELY(y);
1927   int graphic;
1928   int frame;
1929
1930   if (IN_LEV_FIELD(lx, ly))
1931   {
1932     SetRandomAnimationValue(lx, ly);
1933
1934     graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1935     frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1936
1937     /* do not use double (EM style) movement graphic when not moving */
1938     if (graphic_info[graphic].double_movement && !dx && !dy)
1939     {
1940       graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1941       frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1942     }
1943   }
1944   else  /* border element */
1945   {
1946     graphic = el2img(element);
1947     frame = getGraphicAnimationFrame(graphic, -1);
1948   }
1949
1950   if (element == EL_EXPANDABLE_WALL)
1951   {
1952     boolean left_stopped = FALSE, right_stopped = FALSE;
1953
1954     if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1955       left_stopped = TRUE;
1956     if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1957       right_stopped = TRUE;
1958
1959     if (left_stopped && right_stopped)
1960       graphic = IMG_WALL;
1961     else if (left_stopped)
1962     {
1963       graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1964       frame = graphic_info[graphic].anim_frames - 1;
1965     }
1966     else if (right_stopped)
1967     {
1968       graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1969       frame = graphic_info[graphic].anim_frames - 1;
1970     }
1971   }
1972
1973   if (dx || dy)
1974     DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1975   else if (mask_mode == USE_MASKING)
1976     DrawGraphicThruMask(x, y, graphic, frame);
1977   else
1978     DrawGraphic(x, y, graphic, frame);
1979 }
1980
1981 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1982                          int cut_mode, int mask_mode)
1983 {
1984   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1985     DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1986                          cut_mode, mask_mode);
1987 }
1988
1989 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1990                               int cut_mode)
1991 {
1992   DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1993 }
1994
1995 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1996                              int cut_mode)
1997 {
1998   DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1999 }
2000
2001 void DrawLevelElementThruMask(int x, int y, int element)
2002 {
2003   DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
2004 }
2005
2006 void DrawLevelFieldThruMask(int x, int y)
2007 {
2008   DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
2009 }
2010
2011 /* !!! implementation of quicksand is totally broken !!! */
2012 #define IS_CRUMBLED_TILE(x, y, e)                                       \
2013         (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) ||                     \
2014                              !IS_MOVING(x, y) ||                        \
2015                              (e) == EL_QUICKSAND_EMPTYING ||            \
2016                              (e) == EL_QUICKSAND_FAST_EMPTYING))
2017
2018 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
2019                                                int graphic)
2020 {
2021   Bitmap *src_bitmap;
2022   int src_x, src_y;
2023   int width, height, cx, cy;
2024   int sx = SCREENX(x), sy = SCREENY(y);
2025   int crumbled_border_size = graphic_info[graphic].border_size;
2026   int i;
2027
2028   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2029
2030   for (i = 1; i < 4; i++)
2031   {
2032     int dxx = (i & 1 ? dx : 0);
2033     int dyy = (i & 2 ? dy : 0);
2034     int xx = x + dxx;
2035     int yy = y + dyy;
2036     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2037                    BorderElement);
2038
2039     /* check if neighbour field is of same crumble type */
2040     boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
2041                     graphic_info[graphic].class ==
2042                     graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
2043
2044     /* return if check prevents inner corner */
2045     if (same == (dxx == dx && dyy == dy))
2046       return;
2047   }
2048
2049   /* if we reach this point, we have an inner corner */
2050
2051   getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
2052
2053 #if NEW_TILESIZE
2054   width  = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2055   height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
2056   cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2057   cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
2058
2059   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2060              width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
2061 #else
2062   width  = crumbled_border_size;
2063   height = crumbled_border_size;
2064   cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
2065   cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
2066
2067   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2068              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2069 #endif
2070 }
2071
2072 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
2073                                           int dir)
2074 {
2075   Bitmap *src_bitmap;
2076   int src_x, src_y;
2077   int width, height, bx, by, cx, cy;
2078   int sx = SCREENX(x), sy = SCREENY(y);
2079   int crumbled_border_size = graphic_info[graphic].border_size;
2080   int i;
2081
2082   getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
2083
2084   /* draw simple, sloppy, non-corner-accurate crumbled border */
2085
2086 #if 1
2087   width  = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
2088   height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
2089   cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2090   cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2091 #else
2092   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2093   {
2094     width = crumbled_border_size;
2095     height = TILEY;
2096     cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2097     cy = 0;
2098   }
2099   else                                  /* top or bottom crumbled border */
2100   {
2101     width = TILEX;
2102     height = crumbled_border_size;
2103     cx = 0;
2104     cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2105   }
2106 #endif
2107
2108 #if NEW_TILESIZE
2109   BlitBitmap(src_bitmap, drawto_field,
2110              src_x + cx * TILESIZE_VAR / TILESIZE,
2111              src_y + cy * TILESIZE_VAR / TILESIZE,
2112              width * TILESIZE_VAR / TILESIZE,
2113              height * TILESIZE_VAR / TILESIZE,
2114              FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2115              FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2116 #else
2117   BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
2118              width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2119 #endif
2120
2121   /* (remaining middle border part must be at least as big as corner part) */
2122   if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
2123       crumbled_border_size >= TILESIZE / 3)
2124     return;
2125
2126   /* correct corners of crumbled border, if needed */
2127
2128 #if 1
2129   for (i = -1; i <= 1; i+=2)
2130   {
2131     int xx = x + (dir == 0 || dir == 3 ? i : 0);
2132     int yy = y + (dir == 1 || dir == 2 ? i : 0);
2133     int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2134                    BorderElement);
2135
2136     /* check if neighbour field is of same crumble type */
2137     if (IS_CRUMBLED_TILE(xx, yy, element) &&
2138         graphic_info[graphic].class ==
2139         graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2140     {
2141       /* no crumbled corner, but continued crumbled border */
2142
2143       int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2144       int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2145       int b1 = (i == 1 ? crumbled_border_size :
2146                 TILESIZE - 2 * crumbled_border_size);
2147
2148       width  = crumbled_border_size;
2149       height = crumbled_border_size;
2150
2151       if (dir == 1 || dir == 2)
2152       {
2153         cx = c1;
2154         cy = c2;
2155         bx = cx;
2156         by = b1;
2157       }
2158       else
2159       {
2160         cx = c2;
2161         cy = c1;
2162         bx = b1;
2163         by = cy;
2164       }
2165
2166 #if NEW_TILESIZE
2167       BlitBitmap(src_bitmap, drawto_field,
2168                  src_x + bx * TILESIZE_VAR / TILESIZE,
2169                  src_y + by * TILESIZE_VAR / TILESIZE,
2170                  width * TILESIZE_VAR / TILESIZE,
2171                  height * TILESIZE_VAR / TILESIZE,
2172                  FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2173                  FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2174 #else
2175       BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2176                  width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2177 #endif
2178     }
2179   }
2180 #else
2181   if (dir == 1 || dir == 2)             /* left or right crumbled border */
2182   {
2183     for (i = -1; i <= 1; i+=2)
2184     {
2185       int xx = x;
2186       int yy = y + i;
2187       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2188                      BorderElement);
2189
2190       /* check if neighbour field is of same crumble type */
2191       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2192           graphic_info[graphic].class ==
2193           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2194       {
2195         /* no crumbled corner, but continued crumbled border */
2196
2197         width  = crumbled_border_size;
2198         height = crumbled_border_size;
2199         cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2200         cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2201         bx = cx;
2202         by = (i == 1 ? crumbled_border_size :
2203               TILEY - 2 * crumbled_border_size);
2204
2205         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2206                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2207       }
2208     }
2209   }
2210   else                          /* top or bottom crumbled border */
2211   {
2212     for (i = -1; i <= 1; i+=2)
2213     {
2214       int xx = x + i;
2215       int yy = y;
2216       int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2217                      BorderElement);
2218
2219       /* check if neighbour field is of same crumble type */
2220       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2221           graphic_info[graphic].class ==
2222           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2223       {
2224         /* no crumbled corner, but continued crumbled border */
2225
2226         width  = crumbled_border_size;
2227         height = crumbled_border_size;
2228         cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2229         cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2230         bx = (i == 1 ? crumbled_border_size :
2231               TILEX - 2 * crumbled_border_size);
2232         by = cy;
2233
2234         BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2235                    width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2236       }
2237     }
2238   }
2239 #endif
2240 }
2241
2242 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2243 {
2244   int sx = SCREENX(x), sy = SCREENY(y);
2245   int element;
2246   int i;
2247   static int xy[4][2] =
2248   {
2249     { 0, -1 },
2250     { -1, 0 },
2251     { +1, 0 },
2252     { 0, +1 }
2253   };
2254
2255   if (!IN_LEV_FIELD(x, y))
2256     return;
2257
2258   element = TILE_GFX_ELEMENT(x, y);
2259
2260   /* crumble field itself */
2261   if (IS_CRUMBLED_TILE(x, y, element))
2262   {
2263     if (!IN_SCR_FIELD(sx, sy))
2264       return;
2265
2266     for (i = 0; i < 4; i++)
2267     {
2268       int xx = x + xy[i][0];
2269       int yy = y + xy[i][1];
2270
2271       element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2272                  BorderElement);
2273
2274       /* check if neighbour field is of same crumble type */
2275 #if 1
2276       if (IS_CRUMBLED_TILE(xx, yy, element) &&
2277           graphic_info[graphic].class ==
2278           graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2279         continue;
2280 #else
2281       if (IS_CRUMBLED_TILE(xx, yy, element))
2282         continue;
2283 #endif
2284
2285       DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2286     }
2287
2288     if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2289         graphic_info[graphic].anim_frames == 2)
2290     {
2291       for (i = 0; i < 4; i++)
2292       {
2293         int dx = (i & 1 ? +1 : -1);
2294         int dy = (i & 2 ? +1 : -1);
2295
2296         DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2297       }
2298     }
2299
2300     MarkTileDirty(sx, sy);
2301   }
2302   else          /* center field not crumbled -- crumble neighbour fields */
2303   {
2304     for (i = 0; i < 4; i++)
2305     {
2306       int xx = x + xy[i][0];
2307       int yy = y + xy[i][1];
2308       int sxx = sx + xy[i][0];
2309       int syy = sy + xy[i][1];
2310
2311       if (!IN_LEV_FIELD(xx, yy) ||
2312           !IN_SCR_FIELD(sxx, syy))
2313         continue;
2314
2315       if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2316         continue;
2317
2318       element = TILE_GFX_ELEMENT(xx, yy);
2319
2320       if (!IS_CRUMBLED_TILE(xx, yy, element))
2321         continue;
2322
2323       graphic = el_act2crm(element, ACTION_DEFAULT);
2324
2325       DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2326
2327       MarkTileDirty(sxx, syy);
2328     }
2329   }
2330 }
2331
2332 void DrawLevelFieldCrumbled(int x, int y)
2333 {
2334   int graphic;
2335
2336   if (!IN_LEV_FIELD(x, y))
2337     return;
2338
2339 #if 1
2340   /* !!! CHECK THIS !!! */
2341
2342   /*
2343   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2344       GFX_CRUMBLED(GfxElement[x][y]))
2345   */
2346
2347   if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2348       GfxElement[x][y] != EL_UNDEFINED &&
2349       GFX_CRUMBLED(GfxElement[x][y]))
2350   {
2351     DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2352
2353     return;
2354   }
2355 #endif
2356
2357 #if 1
2358   graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2359 #else
2360   graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2361 #endif
2362
2363   DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2364 }
2365
2366 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2367                                    int step_frame)
2368 {
2369   int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2370   int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2371   int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2372   int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2373   int sx = SCREENX(x), sy = SCREENY(y);
2374
2375   DrawGraphic(sx, sy, graphic1, frame1);
2376   DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2377 }
2378
2379 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2380 {
2381   int sx = SCREENX(x), sy = SCREENY(y);
2382   static int xy[4][2] =
2383   {
2384     { 0, -1 },
2385     { -1, 0 },
2386     { +1, 0 },
2387     { 0, +1 }
2388   };
2389   int i;
2390
2391   for (i = 0; i < 4; i++)
2392   {
2393     int xx = x + xy[i][0];
2394     int yy = y + xy[i][1];
2395     int sxx = sx + xy[i][0];
2396     int syy = sy + xy[i][1];
2397
2398     if (!IN_LEV_FIELD(xx, yy) ||
2399         !IN_SCR_FIELD(sxx, syy) ||
2400         !GFX_CRUMBLED(Feld[xx][yy]) ||
2401         IS_MOVING(xx, yy))
2402       continue;
2403
2404     DrawLevelField(xx, yy);
2405   }
2406 }
2407
2408 static int getBorderElement(int x, int y)
2409 {
2410   int border[7][2] =
2411   {
2412     { EL_STEELWALL_TOPLEFT,             EL_INVISIBLE_STEELWALL_TOPLEFT     },
2413     { EL_STEELWALL_TOPRIGHT,            EL_INVISIBLE_STEELWALL_TOPRIGHT    },
2414     { EL_STEELWALL_BOTTOMLEFT,          EL_INVISIBLE_STEELWALL_BOTTOMLEFT  },
2415     { EL_STEELWALL_BOTTOMRIGHT,         EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2416     { EL_STEELWALL_VERTICAL,            EL_INVISIBLE_STEELWALL_VERTICAL    },
2417     { EL_STEELWALL_HORIZONTAL,          EL_INVISIBLE_STEELWALL_HORIZONTAL  },
2418     { EL_STEELWALL,                     EL_INVISIBLE_STEELWALL             }
2419   };
2420   int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2421   int steel_position = (x == -1         && y == -1              ? 0 :
2422                         x == lev_fieldx && y == -1              ? 1 :
2423                         x == -1         && y == lev_fieldy      ? 2 :
2424                         x == lev_fieldx && y == lev_fieldy      ? 3 :
2425                         x == -1         || x == lev_fieldx      ? 4 :
2426                         y == -1         || y == lev_fieldy      ? 5 : 6);
2427
2428   return border[steel_position][steel_type];
2429 }
2430
2431 void DrawScreenElement(int x, int y, int element)
2432 {
2433   DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2434   DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2435 }
2436
2437 void DrawLevelElement(int x, int y, int element)
2438 {
2439   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2440     DrawScreenElement(SCREENX(x), SCREENY(y), element);
2441 }
2442
2443 void DrawScreenField(int x, int y)
2444 {
2445   int lx = LEVELX(x), ly = LEVELY(y);
2446   int element, content;
2447
2448   if (!IN_LEV_FIELD(lx, ly))
2449   {
2450     if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2451       element = EL_EMPTY;
2452     else
2453       element = getBorderElement(lx, ly);
2454
2455     DrawScreenElement(x, y, element);
2456
2457     return;
2458   }
2459
2460   element = Feld[lx][ly];
2461   content = Store[lx][ly];
2462
2463   if (IS_MOVING(lx, ly))
2464   {
2465     int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2466     boolean cut_mode = NO_CUTTING;
2467
2468     if (element == EL_QUICKSAND_EMPTYING ||
2469         element == EL_QUICKSAND_FAST_EMPTYING ||
2470         element == EL_MAGIC_WALL_EMPTYING ||
2471         element == EL_BD_MAGIC_WALL_EMPTYING ||
2472         element == EL_DC_MAGIC_WALL_EMPTYING ||
2473         element == EL_AMOEBA_DROPPING)
2474       cut_mode = CUT_ABOVE;
2475     else if (element == EL_QUICKSAND_FILLING ||
2476              element == EL_QUICKSAND_FAST_FILLING ||
2477              element == EL_MAGIC_WALL_FILLING ||
2478              element == EL_BD_MAGIC_WALL_FILLING ||
2479              element == EL_DC_MAGIC_WALL_FILLING)
2480       cut_mode = CUT_BELOW;
2481
2482 #if 0
2483     if (lx == 9 && ly == 1)
2484       printf("::: %s [%d] [%d, %d] [%d]\n",
2485              EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2486              el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2487              element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2488              element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2489              GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2490 #endif
2491
2492     if (cut_mode == CUT_ABOVE)
2493 #if 1
2494       DrawScreenElement(x, y, element);
2495 #else
2496       DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2497 #endif
2498     else
2499       DrawScreenElement(x, y, EL_EMPTY);
2500
2501     if (horiz_move)
2502       DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2503     else if (cut_mode == NO_CUTTING)
2504       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2505     else
2506     {
2507       DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2508
2509 #if 1
2510       if (cut_mode == CUT_BELOW &&
2511           IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2512         DrawLevelElement(lx, ly + 1, element);
2513 #endif
2514     }
2515
2516     if (content == EL_ACID)
2517     {
2518       int dir = MovDir[lx][ly];
2519       int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2520       int newly = ly + (dir == MV_UP   ? -1 : dir == MV_DOWN  ? +1 : 0);
2521
2522       DrawLevelElementThruMask(newlx, newly, EL_ACID);
2523     }
2524   }
2525   else if (IS_BLOCKED(lx, ly))
2526   {
2527     int oldx, oldy;
2528     int sx, sy;
2529     int horiz_move;
2530     boolean cut_mode = NO_CUTTING;
2531     int element_old, content_old;
2532
2533     Blocked2Moving(lx, ly, &oldx, &oldy);
2534     sx = SCREENX(oldx);
2535     sy = SCREENY(oldy);
2536     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2537                   MovDir[oldx][oldy] == MV_RIGHT);
2538
2539     element_old = Feld[oldx][oldy];
2540     content_old = Store[oldx][oldy];
2541
2542     if (element_old == EL_QUICKSAND_EMPTYING ||
2543         element_old == EL_QUICKSAND_FAST_EMPTYING ||
2544         element_old == EL_MAGIC_WALL_EMPTYING ||
2545         element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2546         element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2547         element_old == EL_AMOEBA_DROPPING)
2548       cut_mode = CUT_ABOVE;
2549
2550     DrawScreenElement(x, y, EL_EMPTY);
2551
2552     if (horiz_move)
2553       DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2554                                NO_CUTTING);
2555     else if (cut_mode == NO_CUTTING)
2556       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2557                                cut_mode);
2558     else
2559       DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2560                                cut_mode);
2561   }
2562   else if (IS_DRAWABLE(element))
2563     DrawScreenElement(x, y, element);
2564   else
2565     DrawScreenElement(x, y, EL_EMPTY);
2566 }
2567
2568 void DrawLevelField(int x, int y)
2569 {
2570   if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2571     DrawScreenField(SCREENX(x), SCREENY(y));
2572   else if (IS_MOVING(x, y))
2573   {
2574     int newx,newy;
2575
2576     Moving2Blocked(x, y, &newx, &newy);
2577     if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2578       DrawScreenField(SCREENX(newx), SCREENY(newy));
2579   }
2580   else if (IS_BLOCKED(x, y))
2581   {
2582     int oldx, oldy;
2583
2584     Blocked2Moving(x, y, &oldx, &oldy);
2585     if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2586       DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2587   }
2588 }
2589
2590 void DrawMiniElement(int x, int y, int element)
2591 {
2592   int graphic;
2593
2594   graphic = el2edimg(element);
2595   DrawMiniGraphic(x, y, graphic);
2596 }
2597
2598 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2599 {
2600   int x = sx + scroll_x, y = sy + scroll_y;
2601
2602   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2603     DrawMiniElement(sx, sy, EL_EMPTY);
2604   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2605     DrawMiniElement(sx, sy, Feld[x][y]);
2606   else
2607     DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2608 }
2609
2610 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2611                                  int x, int y, int xsize, int ysize,
2612                                  int tile_width, int tile_height)
2613 {
2614   Bitmap *src_bitmap;
2615   int src_x, src_y;
2616   int dst_x = startx + x * tile_width;
2617   int dst_y = starty + y * tile_height;
2618   int width  = graphic_info[graphic].width;
2619   int height = graphic_info[graphic].height;
2620   int inner_width_raw  = MAX(width  - 2 * tile_width,  tile_width);
2621   int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
2622   int inner_width  = inner_width_raw  - (inner_width_raw  % tile_width);
2623   int inner_height = inner_height_raw - (inner_height_raw % tile_height);
2624   int inner_sx = (width  >= 3 * tile_width  ? tile_width  : 0);
2625   int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2626   boolean draw_masked = graphic_info[graphic].draw_masked;
2627
2628   getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2629
2630   if (src_bitmap == NULL || width < tile_width || height < tile_height)
2631   {
2632     ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2633     return;
2634   }
2635
2636   src_x += (x == 0 ? 0 : x == xsize - 1 ? width  - tile_width  :
2637             inner_sx + (x - 1) * tile_width  % inner_width);
2638   src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2639             inner_sy + (y - 1) * tile_height % inner_height);
2640
2641   if (draw_masked)
2642   {
2643     SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2644                   dst_x - src_x, dst_y - src_y);
2645     BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2646                      dst_x, dst_y);
2647   }
2648   else
2649     BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2650                dst_x, dst_y);
2651 }
2652
2653 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2654                             int x, int y, int xsize, int ysize, int font_nr)
2655 {
2656   int font_width  = getFontWidth(font_nr);
2657   int font_height = getFontHeight(font_nr);
2658
2659   DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2660                               font_width, font_height);
2661 }
2662
2663 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2664 {
2665   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2666   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2667   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2668   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2669   boolean no_delay = (tape.warp_forward);
2670   unsigned int anim_delay = 0;
2671   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2672   int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2673   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2674   int font_width = getFontWidth(font_nr);
2675   int font_height = getFontHeight(font_nr);
2676   int max_xsize = level.envelope[envelope_nr].xsize;
2677   int max_ysize = level.envelope[envelope_nr].ysize;
2678   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2679   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2680   int xend = max_xsize;
2681   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2682   int xstep = (xstart < xend ? 1 : 0);
2683   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2684   int x, y;
2685
2686   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2687   {
2688     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2689     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2690     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
2691     int sy = SY + (SYSIZE - ysize * font_height) / 2;
2692     int xx, yy;
2693
2694     SetDrawtoField(DRAW_BUFFERED);
2695
2696 #if 1
2697     BlitScreenToBitmap(backbuffer);
2698 #else
2699     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2700 #endif
2701
2702     SetDrawtoField(DRAW_BACKBUFFER);
2703
2704     for (yy = 0; yy < ysize; yy++)
2705       for (xx = 0; xx < xsize; xx++)
2706         DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2707
2708 #if 1
2709     DrawTextBuffer(sx + font_width, sy + font_height,
2710                    level.envelope[envelope_nr].text, font_nr, max_xsize,
2711                    xsize - 2, ysize - 2, 0, mask_mode,
2712                    level.envelope[envelope_nr].autowrap,
2713                    level.envelope[envelope_nr].centered, FALSE);
2714 #else
2715     DrawTextToTextArea(sx + font_width, sy + font_height,
2716                        level.envelope[envelope_nr].text, font_nr, max_xsize,
2717                        xsize - 2, ysize - 2, mask_mode);
2718 #endif
2719
2720     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2721     BackToFront();
2722
2723     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2724   }
2725 }
2726
2727 void ShowEnvelope(int envelope_nr)
2728 {
2729   int element = EL_ENVELOPE_1 + envelope_nr;
2730   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2731   int sound_opening = element_info[element].sound[ACTION_OPENING];
2732   int sound_closing = element_info[element].sound[ACTION_CLOSING];
2733   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2734   boolean no_delay = (tape.warp_forward);
2735   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2736   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2737   int anim_mode = graphic_info[graphic].anim_mode;
2738   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2739                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2740
2741   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
2742
2743   PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2744
2745   if (anim_mode == ANIM_DEFAULT)
2746     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2747
2748   AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2749
2750   if (tape.playing)
2751     Delay(wait_delay_value);
2752   else
2753     WaitForEventToContinue();
2754
2755   PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2756
2757   if (anim_mode != ANIM_NONE)
2758     AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2759
2760   if (anim_mode == ANIM_DEFAULT)
2761     AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2762
2763   game.envelope_active = FALSE;
2764
2765   SetDrawtoField(DRAW_BUFFERED);
2766
2767   redraw_mask |= REDRAW_FIELD;
2768   BackToFront();
2769 }
2770
2771 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2772 {
2773   int border_size = request.border_size;
2774   int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2775   int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2776   int sx = sx_center - request.width  / 2;
2777   int sy = sy_center - request.height / 2;
2778
2779   if (add_border_size)
2780   {
2781     sx += border_size;
2782     sy += border_size;
2783   }
2784
2785   *x = sx;
2786   *y = sy;
2787 }
2788
2789 void DrawEnvelopeRequest(char *text)
2790 {
2791   char *text_final = text;
2792   char *text_door_style = NULL;
2793   int graphic = IMG_BACKGROUND_REQUEST;
2794   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2795   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2796   int font_nr = FONT_REQUEST;
2797   int font_width = getFontWidth(font_nr);
2798   int font_height = getFontHeight(font_nr);
2799   int border_size = request.border_size;
2800   int line_spacing = request.line_spacing;
2801   int line_height = font_height + line_spacing;
2802   int text_width = request.width - 2 * border_size;
2803   int text_height = request.height - 2 * border_size;
2804   int line_length = text_width / font_width;
2805   int max_lines = text_height / line_height;
2806   int width = request.width;
2807   int height = request.height;
2808   int tile_size = request.step_offset;
2809   int x_steps = width  / tile_size;
2810   int y_steps = height / tile_size;
2811   int sx, sy;
2812   int i, x, y;
2813
2814   if (request.wrap_single_words)
2815   {
2816     char *src_text_ptr, *dst_text_ptr;
2817
2818     text_door_style = checked_malloc(2 * strlen(text) + 1);
2819
2820     src_text_ptr = text;
2821     dst_text_ptr = text_door_style;
2822
2823     while (*src_text_ptr)
2824     {
2825       if (*src_text_ptr == ' ' ||
2826           *src_text_ptr == '?' ||
2827           *src_text_ptr == '!')
2828         *dst_text_ptr++ = '\n';
2829
2830       if (*src_text_ptr != ' ')
2831         *dst_text_ptr++ = *src_text_ptr;
2832
2833       src_text_ptr++;
2834     }
2835
2836     *dst_text_ptr = '\0';
2837
2838     text_final = text_door_style;
2839   }
2840
2841   setRequestPosition(&sx, &sy, FALSE);
2842
2843   ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2844
2845   for (y = 0; y < y_steps; y++)
2846     for (x = 0; x < x_steps; x++)
2847       DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2848                                   x, y, x_steps, y_steps,
2849                                   tile_size, tile_size);
2850
2851   DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2852                  line_length, -1, max_lines, line_spacing, mask_mode,
2853                  request.autowrap, request.centered, FALSE);
2854
2855   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2856     RedrawGadget(tool_gadget[i]);
2857
2858   // store readily prepared envelope request for later use when animating
2859   BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2860
2861 #if 0
2862   // !!! TEST !!!
2863   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2864   BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2865
2866   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2867   BackToFront();
2868
2869   Delay(3000);
2870
2871   BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2872
2873   redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2874   BackToFront();
2875
2876   Delay(1000);
2877 #endif
2878
2879   if (text_door_style)
2880     free(text_door_style);
2881 }
2882
2883 #if 1
2884
2885 void AnimateEnvelopeRequest(int anim_mode, int action)
2886 {
2887   int graphic = IMG_BACKGROUND_REQUEST;
2888   boolean draw_masked = graphic_info[graphic].draw_masked;
2889 #if 1
2890   int delay_value_normal = request.step_delay;
2891   int delay_value_fast = delay_value_normal / 2;
2892 #else
2893   int delay_value_normal = GameFrameDelay;
2894   int delay_value_fast = FfwdFrameDelay;
2895 #endif
2896   boolean ffwd_delay = (tape.playing && tape.fast_forward);
2897   boolean no_delay = (tape.warp_forward);
2898   int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2899   int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2900   unsigned int anim_delay = 0;
2901
2902   int width = request.width;
2903   int height = request.height;
2904   int tile_size = request.step_offset;
2905   int max_xsize = width  / tile_size;
2906   int max_ysize = height / tile_size;
2907   int max_xsize_inner = max_xsize - 2;
2908   int max_ysize_inner = max_ysize - 2;
2909
2910   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2911   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2912   int xend = max_xsize_inner;
2913   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2914   int xstep = (xstart < xend ? 1 : 0);
2915   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2916   int x, y;
2917
2918   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2919   {
2920     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2921     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2922     int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2923     int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2924     int src_x = sx_center - width  / 2;
2925     int src_y = sy_center - height / 2;
2926     int dst_x = sx_center - xsize * tile_size / 2;
2927     int dst_y = sy_center - ysize * tile_size / 2;
2928     int xsize_size_left = (xsize - 1) * tile_size;
2929     int ysize_size_top  = (ysize - 1) * tile_size;
2930     int max_xsize_pos = (max_xsize - 1) * tile_size;
2931     int max_ysize_pos = (max_ysize - 1) * tile_size;
2932     int xx, yy;
2933
2934     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2935
2936 #if 1
2937     for (yy = 0; yy < 2; yy++)
2938     {
2939       for (xx = 0; xx < 2; xx++)
2940       {
2941         int src_xx = src_x + xx * max_xsize_pos;
2942         int src_yy = src_y + yy * max_ysize_pos;
2943         int dst_xx = dst_x + xx * xsize_size_left;
2944         int dst_yy = dst_y + yy * ysize_size_top;
2945         int xx_size = (xx ? tile_size : xsize_size_left);
2946         int yy_size = (yy ? tile_size : ysize_size_top);
2947
2948         if (draw_masked)
2949           BlitBitmapMasked(bitmap_db_cross, backbuffer,
2950                            src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2951         else
2952           BlitBitmap(bitmap_db_cross, backbuffer,
2953                      src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2954       }
2955     }
2956 #else
2957     BlitBitmap(bitmap_db_cross, backbuffer,
2958                src_x, src_y,
2959                xsize_size_left, ysize_size_top,
2960                dst_x, dst_y);
2961     BlitBitmap(bitmap_db_cross, backbuffer,
2962                src_x + max_xsize_pos, src_y,
2963                tile_size, ysize_size_top,
2964                dst_x + xsize_size_left, dst_y);
2965     BlitBitmap(bitmap_db_cross, backbuffer,
2966                src_x, src_y + max_ysize_pos,
2967                xsize_size_left, tile_size,
2968                dst_x, dst_y + ysize_size_top);
2969     BlitBitmap(bitmap_db_cross, backbuffer,
2970                src_x + max_xsize_pos, src_y + max_ysize_pos,
2971                tile_size, tile_size,
2972                dst_x + xsize_size_left, dst_y + ysize_size_top);
2973 #endif
2974
2975 #if 1
2976     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2977     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2978 #else
2979     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2980 #endif
2981
2982 #if 1
2983     DoAnimation();
2984     BackToFront();
2985 #else
2986     BackToFront();
2987 #endif
2988
2989     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2990   }
2991 }
2992
2993 #else
2994
2995 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2996 {
2997 #if 0
2998   int envelope_nr = 0;
2999 #endif
3000 #if 1
3001   int graphic = IMG_BACKGROUND_REQUEST;
3002 #else
3003   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3004 #endif
3005   Bitmap *src_bitmap = graphic_info[graphic].bitmap;
3006   int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
3007   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3008   boolean no_delay = (tape.warp_forward);
3009   unsigned int anim_delay = 0;
3010   int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
3011   int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
3012 #if 1
3013   int max_word_len = maxWordLengthInString(text);
3014   int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
3015 #else
3016   int font_nr = FONT_ENVELOPE_1 + envelope_nr;
3017 #endif
3018   int font_width = getFontWidth(font_nr);
3019   int font_height = getFontHeight(font_nr);
3020   int line_spacing = 2 * 1;
3021 #if 1
3022
3023 #if 1
3024   int max_xsize = DXSIZE / font_width;
3025   // int max_ysize = DYSIZE / font_height;
3026   int max_ysize = DYSIZE / (font_height + line_spacing);
3027 #else
3028   int max_xsize = 7;    /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3029   int max_ysize = 13;   /* tools.c: MAX_REQUEST_LINES == 13 */
3030 #endif
3031
3032 #else
3033   int max_xsize = level.envelope[envelope_nr].xsize;
3034   int max_ysize = level.envelope[envelope_nr].ysize;
3035 #endif
3036   int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
3037   int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
3038   int xend = max_xsize;
3039   int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
3040   int xstep = (xstart < xend ? 1 : 0);
3041   int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
3042   int x, y;
3043
3044 #if 1
3045   char *text_ptr;
3046   char *text_copy = getStringCopy(text);
3047 #else
3048 #if 1
3049   font_nr = FONT_TEXT_2;
3050
3051   if (maxWordLengthInString(text) > 7)  /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
3052   {
3053     max_xsize = 10;     /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3054     font_nr = FONT_TEXT_1;
3055   }
3056 #else
3057   int max_word_len = 0;
3058   char *text_ptr;
3059   char *text_copy = getStringCopy(text);
3060
3061   font_nr = FONT_TEXT_2;
3062
3063   for (text_ptr = text; *text_ptr; text_ptr++)
3064   {
3065     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
3066
3067     if (max_word_len > 7)       /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
3068     {
3069       max_xsize = 10;   /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
3070       font_nr = FONT_TEXT_1;
3071
3072       break;
3073     }
3074   }
3075 #endif
3076 #endif
3077
3078 #if 1
3079   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3080     if (*text_ptr == ' ')
3081       *text_ptr = '\n';
3082 #endif
3083
3084 #if 1
3085   dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
3086   dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
3087 #else
3088   dDX = SX + SXSIZE / 2 - max_xsize * font_width  / 2 - DX;
3089   dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
3090 #endif
3091
3092   for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
3093   {
3094     int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
3095     int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
3096     int sx = SX + (SXSIZE - xsize * font_width)  / 2;
3097     // int sy = SX + (SYSIZE - ysize * font_height) / 2;
3098     int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
3099     int xx, yy;
3100
3101 #if 1
3102     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3103 #else
3104     SetDrawtoField(DRAW_BUFFERED);
3105
3106 #if 1
3107     BlitScreenToBitmap(backbuffer);
3108 #else
3109     BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3110 #endif
3111
3112     SetDrawtoField(DRAW_BACKBUFFER);
3113 #endif
3114
3115     for (yy = 0; yy < ysize; yy++)
3116       for (xx = 0; xx < xsize; xx++)
3117         DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
3118                                     getFontWidth(font_nr),
3119                                     getFontHeight(font_nr) + line_spacing);
3120
3121 #if 1
3122
3123 #if 1
3124     DrawTextBuffer(sx + font_width, sy + font_height + 8,
3125                    text_copy, font_nr, max_xsize,
3126                    xsize - 2, ysize - 2, line_spacing, mask_mode,
3127                    FALSE, TRUE, FALSE);
3128 #else
3129     DrawTextBuffer(sx + font_width, sy + font_height,
3130                    level.envelope[envelope_nr].text, font_nr, max_xsize,
3131                    xsize - 2, ysize - 2, 0, mask_mode,
3132                    level.envelope[envelope_nr].autowrap,
3133                    level.envelope[envelope_nr].centered, FALSE);
3134 #endif
3135
3136 #else
3137     DrawTextToTextArea(sx + font_width, sy + font_height,
3138                        level.envelope[envelope_nr].text, font_nr, max_xsize,
3139                        xsize - 2, ysize - 2, mask_mode);
3140 #endif
3141
3142     /* copy request gadgets to door backbuffer */
3143 #if 1
3144     /*
3145     if ((ysize - 2) > 13)
3146       BlitBitmap(bitmap_db_door, drawto,
3147                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3148                  DOOR_GFX_PAGEY1 + 13 * font_height,
3149                  (xsize - 2) * font_width,
3150                  (ysize - 2 - 13) * font_height,
3151                  sx + font_width,
3152                  sy + font_height * (1 + 13));
3153     */
3154     if ((ysize - 2) > 13)
3155       BlitBitmap(bitmap_db_door, drawto,
3156                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3157                  DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
3158                  (xsize - 2) * font_width,
3159                  (ysize - 2 - 13) * (font_height + line_spacing),
3160                  sx + font_width,
3161                  sy + (font_height + line_spacing) * (1 + 13));
3162 #else
3163     if ((ysize - 2) > 13)
3164       BlitBitmap(bitmap_db_door, drawto,
3165                  DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
3166                  DOOR_GFX_PAGEY1 + 13 * font_height,
3167                  (xsize - 2) * font_width,
3168                  (ysize - 2 - 13) * font_height,
3169                  sx + font_width,
3170                  sy + font_height * (1 + 13));
3171 #endif
3172
3173 #if 1
3174     redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3175     // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3176 #else
3177     redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3178 #endif
3179
3180 #if 1
3181     DoAnimation();
3182     BackToFront();
3183 #else
3184     BackToFront();
3185 #endif
3186
3187     WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3188   }
3189
3190 #if 1
3191   free(text_copy);
3192 #endif
3193 }
3194
3195 #endif
3196
3197 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3198 {
3199 #if 1
3200   int last_game_status = game_status;   /* save current game status */
3201   // int last_draw_background_mask = gfx.draw_background_mask;
3202 #endif
3203 #if 1
3204   int graphic = IMG_BACKGROUND_REQUEST;
3205   int sound_opening = SND_REQUEST_OPENING;
3206   int sound_closing = SND_REQUEST_CLOSING;
3207 #else
3208   int envelope_nr = 0;
3209   int element = EL_ENVELOPE_1 + envelope_nr;
3210   int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3211   int sound_opening = element_info[element].sound[ACTION_OPENING];
3212   int sound_closing = element_info[element].sound[ACTION_CLOSING];
3213 #endif
3214 #if 0
3215   boolean ffwd_delay = (tape.playing && tape.fast_forward);
3216   boolean no_delay = (tape.warp_forward);
3217   int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3218   int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3219 #endif
3220   int anim_mode = graphic_info[graphic].anim_mode;
3221   int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3222                         anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3223 #if 0
3224   char *text_copy = getStringCopy(text);
3225   char *text_ptr;
3226
3227   for (text_ptr = text_copy; *text_ptr; text_ptr++)
3228     if (*text_ptr == ' ')
3229       *text_ptr = '\n';
3230 #endif
3231
3232 #if 1
3233   if (game_status == GAME_MODE_PLAYING)
3234   {
3235     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3236       BlitScreenToBitmap_EM(backbuffer);
3237     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3238       BlitScreenToBitmap_SP(backbuffer);
3239     else
3240     {
3241       BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3242     }
3243   }
3244
3245   SetDrawtoField(DRAW_BACKBUFFER);
3246
3247   // SetDrawBackgroundMask(REDRAW_NONE);
3248
3249   if (action == ACTION_OPENING)
3250   {
3251     BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3252
3253 #if 1
3254   if (req_state & REQ_ASK)
3255   {
3256     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3257     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3258   }
3259   else if (req_state & REQ_CONFIRM)
3260   {
3261     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3262   }
3263   else if (req_state & REQ_PLAYER)
3264   {
3265     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3266     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3267     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3268     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3269   }
3270 #endif
3271
3272 #if 1
3273     DrawEnvelopeRequest(text);
3274 #else
3275     DrawEnvelopeRequest(text_copy);
3276 #endif
3277
3278     if (game_status != GAME_MODE_MAIN)
3279       InitAnimation();
3280   }
3281
3282   /* force DOOR font inside door area */
3283   game_status = GAME_MODE_PSEUDO_DOOR;
3284 #endif
3285
3286   game.envelope_active = TRUE;  /* needed for RedrawPlayfield() events */
3287
3288   if (action == ACTION_OPENING)
3289   {
3290     PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3291
3292     if (anim_mode == ANIM_DEFAULT)
3293       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
3294
3295     AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
3296
3297 #if 0
3298     if (tape.playing)
3299       Delay(wait_delay_value);
3300     else
3301       WaitForEventToContinue();
3302 #endif
3303   }
3304   else
3305   {
3306     PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3307
3308     if (anim_mode != ANIM_NONE)
3309       AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
3310
3311     if (anim_mode == ANIM_DEFAULT)
3312       AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
3313   }
3314
3315   game.envelope_active = FALSE;
3316
3317 #if 1
3318   // game_status = last_game_status;    /* restore current game status */
3319
3320   if (action == ACTION_CLOSING)
3321   {
3322     if (game_status != GAME_MODE_MAIN)
3323       StopAnimation();
3324
3325     BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3326   }
3327 #else
3328   SetDrawtoField(DRAW_BUFFERED);
3329 #endif
3330
3331   // SetDrawBackgroundMask(last_draw_background_mask);
3332
3333 #if 1
3334   redraw_mask = REDRAW_FIELD;
3335   // redraw_mask |= REDRAW_ALL;
3336 #else
3337   redraw_mask |= REDRAW_FIELD;
3338 #endif
3339
3340 #if 1
3341   if (game_status == GAME_MODE_MAIN)
3342     DoAnimation();
3343
3344   BackToFront();
3345
3346   /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3347   game_status = last_game_status;       /* restore current game status */
3348
3349 #if 1
3350   if (action == ACTION_CLOSING &&
3351       game_status == GAME_MODE_PLAYING &&
3352       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3353     SetDrawtoField(DRAW_BUFFERED);
3354 #else
3355   if (game_status == GAME_MODE_PLAYING &&
3356       level.game_engine_type == GAME_ENGINE_TYPE_RND)
3357     SetDrawtoField(DRAW_BUFFERED);
3358 #endif
3359
3360 #else
3361   BackToFront();
3362 #endif
3363
3364 #if 0
3365   free(text_copy);
3366 #endif
3367 }
3368
3369 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3370 {
3371   Bitmap *src_bitmap;
3372   int src_x, src_y;
3373   int graphic = el2preimg(element);
3374
3375   getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3376   BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3377 }
3378
3379 void DrawLevel()
3380 {
3381   int x,y;
3382
3383 #if 1
3384   SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3385   SetDrawBackgroundMask(REDRAW_FIELD);
3386 #else
3387   SetDrawBackgroundMask(REDRAW_NONE);
3388 #endif
3389
3390   ClearField();
3391
3392   for (x = BX1; x <= BX2; x++)
3393     for (y = BY1; y <= BY2; y++)
3394       DrawScreenField(x, y);
3395
3396   redraw_mask |= REDRAW_FIELD;
3397 }
3398
3399 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3400 {
3401   int x,y;
3402
3403   for (x = 0; x < size_x; x++)
3404     for (y = 0; y < size_y; y++)
3405       DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3406
3407   redraw_mask |= REDRAW_FIELD;
3408 }
3409
3410 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3411 {
3412   boolean show_level_border = (BorderElement != EL_EMPTY);
3413   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3414   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3415   int tile_size = preview.tile_size;
3416   int preview_width  = preview.xsize * tile_size;
3417   int preview_height = preview.ysize * tile_size;
3418   int real_preview_xsize = MIN(level_xsize, preview.xsize);
3419   int real_preview_ysize = MIN(level_ysize, preview.ysize);
3420   int real_preview_width  = real_preview_xsize * tile_size;
3421   int real_preview_height = real_preview_ysize * tile_size;
3422   int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3423   int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3424   int x, y;
3425
3426 #if 1
3427   if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
3428     return;
3429 #endif
3430
3431 #if 0
3432   dst_x += (preview_width  - real_preview_width)  / 2;
3433   dst_y += (preview_height - real_preview_height) / 2;
3434
3435   DrawBackground(dst_x, dst_y, real_preview_width, real_preview_height);
3436 #else
3437   DrawBackground(dst_x, dst_y, preview_width, preview_height);
3438
3439   dst_x += (preview_width  - real_preview_width)  / 2;
3440   dst_y += (preview_height - real_preview_height) / 2;
3441 #endif
3442
3443   for (x = 0; x < real_preview_xsize; x++)
3444   {
3445     for (y = 0; y < real_preview_ysize; y++)
3446     {
3447       int lx = from_x + x + (show_level_border ? -1 : 0);
3448       int ly = from_y + y + (show_level_border ? -1 : 0);
3449       int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3450                      getBorderElement(lx, ly));
3451
3452       DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3453                          element, tile_size);
3454     }
3455   }
3456
3457   redraw_mask |= REDRAW_MICROLEVEL;
3458 }
3459
3460 #define MICROLABEL_EMPTY                0
3461 #define MICROLABEL_LEVEL_NAME           1
3462 #define MICROLABEL_LEVEL_AUTHOR_HEAD    2
3463 #define MICROLABEL_LEVEL_AUTHOR         3
3464 #define MICROLABEL_IMPORTED_FROM_HEAD   4
3465 #define MICROLABEL_IMPORTED_FROM        5
3466 #define MICROLABEL_IMPORTED_BY_HEAD     6
3467 #define MICROLABEL_IMPORTED_BY          7
3468
3469 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3470 {
3471   int max_text_width = SXSIZE;
3472   int font_width = getFontWidth(font_nr);
3473
3474   if (pos->align == ALIGN_CENTER)
3475     max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3476   else if (pos->align == ALIGN_RIGHT)
3477     max_text_width = pos->x;
3478   else
3479     max_text_width = SXSIZE - pos->x;
3480
3481   return max_text_width / font_width;
3482 }
3483
3484 static void DrawPreviewLevelLabelExt(int mode)
3485 {
3486   struct TextPosInfo *pos = &menu.main.text.level_info_2;
3487   char label_text[MAX_OUTPUT_LINESIZE + 1];
3488   int max_len_label_text;
3489 #if 1
3490   int font_nr = pos->font;
3491   int i;
3492
3493   if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3494     return;
3495
3496   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3497       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3498       mode == MICROLABEL_IMPORTED_BY_HEAD)
3499     font_nr = pos->font_alt;
3500 #else
3501   int font_nr = FONT_TEXT_2;
3502   int i;
3503
3504   if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3505       mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3506       mode == MICROLABEL_IMPORTED_BY_HEAD)
3507     font_nr = FONT_TEXT_3;
3508 #endif
3509
3510 #if 1
3511   max_len_label_text = getMaxTextLength(pos, font_nr);
3512 #else
3513   max_len_label_text = SXSIZE / getFontWidth(font_nr);
3514 #endif
3515
3516 #if 1
3517   if (pos->size != -1)
3518     max_len_label_text = pos->size;
3519 #endif
3520
3521   for (i = 0; i < max_len_label_text; i++)
3522     label_text[i] = ' ';
3523   label_text[max_len_label_text] = '\0';
3524
3525   if (strlen(label_text) > 0)
3526   {
3527 #if 1
3528     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3529 #else
3530     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3531     int lypos = MICROLABEL2_YPOS;
3532
3533     DrawText(lxpos, lypos, label_text, font_nr);
3534 #endif
3535   }
3536
3537   strncpy(label_text,
3538           (mode == MICROLABEL_LEVEL_NAME ? level.name :
3539            mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3540            mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3541            mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3542            mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3543            mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3544            mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3545           max_len_label_text);
3546   label_text[max_len_label_text] = '\0';
3547
3548   if (strlen(label_text) > 0)
3549   {
3550 #if 1
3551     DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3552 #else
3553     int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3554     int lypos = MICROLABEL2_YPOS;
3555
3556     DrawText(lxpos, lypos, label_text, font_nr);
3557 #endif
3558   }
3559
3560   redraw_mask |= REDRAW_MICROLEVEL;
3561 }
3562
3563 static void DrawPreviewLevelExt(boolean restart)
3564 {
3565   static unsigned int scroll_delay = 0;
3566   static unsigned int label_delay = 0;
3567   static int from_x, from_y, scroll_direction;
3568   static int label_state, label_counter;
3569   unsigned int scroll_delay_value = preview.step_delay;
3570   boolean show_level_border = (BorderElement != EL_EMPTY);
3571   int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3572   int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3573   int last_game_status = game_status;           /* save current game status */
3574
3575 #if 0
3576   /* force PREVIEW font on preview level */
3577   game_status = GAME_MODE_PSEUDO_PREVIEW;
3578 #endif
3579
3580   if (restart)
3581   {
3582     from_x = 0;
3583     from_y = 0;
3584
3585     if (preview.anim_mode == ANIM_CENTERED)
3586     {
3587       if (level_xsize > preview.xsize)
3588         from_x = (level_xsize - preview.xsize) / 2;
3589       if (level_ysize > preview.ysize)
3590         from_y = (level_ysize - preview.ysize) / 2;
3591     }
3592
3593     from_x += preview.xoffset;
3594     from_y += preview.yoffset;
3595
3596     scroll_direction = MV_RIGHT;
3597     label_state = 1;
3598     label_counter = 0;
3599
3600     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3601     DrawPreviewLevelLabelExt(label_state);
3602
3603     /* initialize delay counters */
3604     DelayReached(&scroll_delay, 0);
3605     DelayReached(&label_delay, 0);
3606
3607     if (leveldir_current->name)
3608     {
3609       struct TextPosInfo *pos = &menu.main.text.level_info_1;
3610       char label_text[MAX_OUTPUT_LINESIZE + 1];
3611 #if 1
3612       int font_nr = pos->font;
3613 #else
3614       int font_nr = FONT_TEXT_1;
3615 #endif
3616 #if 1
3617       int max_len_label_text = getMaxTextLength(pos, font_nr);
3618 #else
3619       int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3620 #endif
3621 #if 0
3622       int text_width;
3623       int lxpos, lypos;
3624 #endif
3625
3626 #if 1
3627       if (pos->size != -1)
3628         max_len_label_text = pos->size;
3629 #endif
3630
3631       strncpy(label_text, leveldir_current->name, max_len_label_text);
3632       label_text[max_len_label_text] = '\0';
3633
3634 #if 1
3635       if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
3636         DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3637 #else
3638       lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3639       lypos = SY + MICROLABEL1_YPOS;
3640
3641       DrawText(lxpos, lypos, label_text, font_nr);
3642 #endif
3643     }
3644
3645     game_status = last_game_status;     /* restore current game status */
3646
3647     return;
3648   }
3649
3650   /* scroll preview level, if needed */
3651   if (preview.anim_mode != ANIM_NONE &&
3652       (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3653       DelayReached(&scroll_delay, scroll_delay_value))
3654   {
3655     switch (scroll_direction)
3656     {
3657       case MV_LEFT:
3658         if (from_x > 0)
3659         {
3660           from_x -= preview.step_offset;
3661           from_x = (from_x < 0 ? 0 : from_x);
3662         }
3663         else
3664           scroll_direction = MV_UP;
3665         break;
3666
3667       case MV_RIGHT:
3668         if (from_x < level_xsize - preview.xsize)
3669         {
3670           from_x += preview.step_offset;
3671           from_x = (from_x > level_xsize - preview.xsize ?
3672                     level_xsize - preview.xsize : from_x);
3673         }
3674         else
3675           scroll_direction = MV_DOWN;
3676         break;
3677
3678       case MV_UP:
3679         if (from_y > 0)
3680         {
3681           from_y -= preview.step_offset;
3682           from_y = (from_y < 0 ? 0 : from_y);
3683         }
3684         else
3685           scroll_direction = MV_RIGHT;
3686         break;
3687
3688       case MV_DOWN:
3689         if (from_y < level_ysize - preview.ysize)
3690         {
3691           from_y += preview.step_offset;
3692           from_y = (from_y > level_ysize - preview.ysize ?
3693                     level_ysize - preview.ysize : from_y);
3694         }
3695         else
3696           scroll_direction = MV_LEFT;
3697         break;
3698
3699       default:
3700         break;
3701     }
3702
3703     DrawPreviewLevelPlayfieldExt(from_x, from_y);
3704   }
3705
3706   /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3707   /* redraw micro level label, if needed */
3708   if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3709       !strEqual(level.author, ANONYMOUS_NAME) &&
3710       !strEqual(level.author, leveldir_current->name) &&
3711       DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3712   {
3713     int max_label_counter = 23;
3714
3715     if (leveldir_current->imported_from != NULL &&
3716         strlen(leveldir_current->imported_from) > 0)
3717       max_label_counter += 14;
3718     if (leveldir_current->imported_by != NULL &&
3719         strlen(leveldir_current->imported_by) > 0)
3720       max_label_counter += 14;
3721
3722     label_counter = (label_counter + 1) % max_label_counter;
3723     label_state = (label_counter >= 0 && label_counter <= 7 ?
3724                    MICROLABEL_LEVEL_NAME :
3725                    label_counter >= 9 && label_counter <= 12 ?
3726                    MICROLABEL_LEVEL_AUTHOR_HEAD :
3727                    label_counter >= 14 && label_counter <= 21 ?
3728                    MICROLABEL_LEVEL_AUTHOR :
3729                    label_counter >= 23 && label_counter <= 26 ?
3730                    MICROLABEL_IMPORTED_FROM_HEAD :
3731                    label_counter >= 28 && label_counter <= 35 ?
3732                    MICROLABEL_IMPORTED_FROM :
3733                    label_counter >= 37 && label_counter <= 40 ?
3734                    MICROLABEL_IMPORTED_BY_HEAD :
3735                    label_counter >= 42 && label_counter <= 49 ?
3736                    MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3737
3738     if (leveldir_current->imported_from == NULL &&
3739         (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3740          label_state == MICROLABEL_IMPORTED_FROM))
3741       label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3742                      MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3743
3744     DrawPreviewLevelLabelExt(label_state);
3745   }
3746
3747   game_status = last_game_status;       /* restore current game status */
3748 }
3749
3750 void DrawPreviewLevelInitial()
3751 {
3752   DrawPreviewLevelExt(TRUE);
3753 }
3754
3755 void DrawPreviewLevelAnimation()
3756 {
3757   DrawPreviewLevelExt(FALSE);
3758 }
3759
3760 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3761                                     int graphic, int sync_frame, int mask_mode)
3762 {
3763   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3764
3765   if (mask_mode == USE_MASKING)
3766     DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3767   else
3768     DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3769 }
3770
3771 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3772                                          int graphic, int sync_frame,
3773                                          int mask_mode)
3774 {
3775   int frame = getGraphicAnimationFrame(graphic, sync_frame);
3776
3777   if (mask_mode == USE_MASKING)
3778     DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3779   else
3780     DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3781 }
3782
3783 inline void DrawGraphicAnimation(int x, int y, int graphic)
3784 {
3785   int lx = LEVELX(x), ly = LEVELY(y);
3786
3787   if (!IN_SCR_FIELD(x, y))
3788     return;
3789
3790 #if NEW_TILESIZE
3791   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3792                           graphic, GfxFrame[lx][ly], NO_MASKING);
3793 #else
3794   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3795                           graphic, GfxFrame[lx][ly], NO_MASKING);
3796 #endif
3797   MarkTileDirty(x, y);
3798 }
3799
3800 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3801 {
3802   int lx = LEVELX(x), ly = LEVELY(y);
3803
3804   if (!IN_SCR_FIELD(x, y))
3805     return;
3806
3807   DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3808                           graphic, GfxFrame[lx][ly], NO_MASKING);
3809   MarkTileDirty(x, y);
3810 }
3811
3812 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3813 {
3814   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3815 }
3816
3817 void DrawLevelElementAnimation(int x, int y, int element)
3818 {
3819   int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3820
3821   DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3822 }
3823
3824 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3825 {
3826   int sx = SCREENX(x), sy = SCREENY(y);
3827
3828   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3829     return;
3830
3831   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3832     return;
3833
3834   DrawGraphicAnimation(sx, sy, graphic);
3835
3836 #if 1
3837   if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3838     DrawLevelFieldCrumbled(x, y);
3839 #else
3840   if (GFX_CRUMBLED(Feld[x][y]))
3841     DrawLevelFieldCrumbled(x, y);
3842 #endif
3843 }
3844
3845 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3846 {
3847   int sx = SCREENX(x), sy = SCREENY(y);
3848   int graphic;
3849
3850   if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3851     return;
3852
3853   graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3854
3855   if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3856     return;
3857
3858   DrawGraphicAnimation(sx, sy, graphic);
3859
3860   if (GFX_CRUMBLED(element))
3861     DrawLevelFieldCrumbled(x, y);
3862 }
3863
3864 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3865 {
3866   if (player->use_murphy)
3867   {
3868     /* this works only because currently only one player can be "murphy" ... */
3869     static int last_horizontal_dir = MV_LEFT;
3870     int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3871
3872     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3873       last_horizontal_dir = move_dir;
3874
3875     if (graphic == IMG_SP_MURPHY)       /* undefined => use special graphic */
3876     {
3877       int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3878
3879       graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3880     }
3881
3882     return graphic;
3883   }
3884   else
3885     return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3886 }
3887
3888 static boolean equalGraphics(int graphic1, int graphic2)
3889 {
3890   struct GraphicInfo *g1 = &graphic_info[graphic1];
3891   struct GraphicInfo *g2 = &graphic_info[graphic2];
3892
3893   return (g1->bitmap      == g2->bitmap &&
3894           g1->src_x       == g2->src_x &&
3895           g1->src_y       == g2->src_y &&
3896           g1->anim_frames == g2->anim_frames &&
3897           g1->anim_delay  == g2->anim_delay &&
3898           g1->anim_mode   == g2->anim_mode);
3899 }
3900
3901 void DrawAllPlayers()
3902 {
3903   int i;
3904
3905   for (i = 0; i < MAX_PLAYERS; i++)
3906     if (stored_player[i].active)
3907       DrawPlayer(&stored_player[i]);
3908 }
3909
3910 void DrawPlayerField(int x, int y)
3911 {
3912   if (!IS_PLAYER(x, y))
3913     return;
3914
3915   DrawPlayer(PLAYERINFO(x, y));
3916 }
3917
3918 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3919
3920 void DrawPlayer(struct PlayerInfo *player)
3921 {
3922   int jx = player->jx;
3923   int jy = player->jy;
3924   int move_dir = player->MovDir;
3925   int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3926   int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? +1 : 0);
3927   int last_jx = (player->is_moving ? jx - dx : jx);
3928   int last_jy = (player->is_moving ? jy - dy : jy);
3929   int next_jx = jx + dx;
3930   int next_jy = jy + dy;
3931   boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3932   boolean player_is_opaque = FALSE;
3933   int sx = SCREENX(jx), sy = SCREENY(jy);
3934   int sxx = 0, syy = 0;
3935   int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3936   int graphic;
3937   int action = ACTION_DEFAULT;
3938   int last_player_graphic = getPlayerGraphic(player, move_dir);
3939   int last_player_frame = player->Frame;
3940   int frame = 0;
3941
3942   /* GfxElement[][] is set to the element the player is digging or collecting;
3943      remove also for off-screen player if the player is not moving anymore */
3944   if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3945     GfxElement[jx][jy] = EL_UNDEFINED;
3946
3947   if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3948     return;
3949
3950 #if DEBUG
3951   if (!IN_LEV_FIELD(jx, jy))
3952   {
3953     printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3954     printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3955     printf("DrawPlayerField(): This should never happen!\n");
3956     return;
3957   }
3958 #endif
3959
3960   if (element == EL_EXPLOSION)
3961     return;
3962
3963   action = (player->is_pushing    ? ACTION_PUSHING         :
3964             player->is_digging    ? ACTION_DIGGING         :
3965             player->is_collecting ? ACTION_COLLECTING      :
3966             player->is_moving     ? ACTION_MOVING          :
3967             player->is_snapping   ? ACTION_SNAPPING        :
3968             player->is_dropping   ? ACTION_DROPPING        :
3969             player->is_waiting    ? player->action_waiting : ACTION_DEFAULT);
3970
3971   if (player->is_waiting)
3972     move_dir = player->dir_waiting;
3973
3974   InitPlayerGfxAnimation(player, action, move_dir);
3975
3976   /* ----------------------------------------------------------------------- */
3977   /* draw things in the field the player is leaving, if needed               */
3978   /* ----------------------------------------------------------------------- */
3979
3980   if (player->is_moving)
3981   {
3982     if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3983     {
3984       DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3985
3986       if (last_element == EL_DYNAMITE_ACTIVE ||
3987           last_element == EL_EM_DYNAMITE_ACTIVE ||
3988           last_element == EL_SP_DISK_RED_ACTIVE)
3989         DrawDynamite(last_jx, last_jy);
3990       else
3991         DrawLevelFieldThruMask(last_jx, last_jy);
3992     }
3993     else if (last_element == EL_DYNAMITE_ACTIVE ||
3994              last_element == EL_EM_DYNAMITE_ACTIVE ||
3995              last_element == EL_SP_DISK_RED_ACTIVE)
3996       DrawDynamite(last_jx, last_jy);
3997 #if 0
3998     /* !!! this is not enough to prevent flickering of players which are
3999        moving next to each others without a free tile between them -- this
4000        can only be solved by drawing all players layer by layer (first the
4001        background, then the foreground etc.) !!! => TODO */
4002     else if (!IS_PLAYER(last_jx, last_jy))
4003       DrawLevelField(last_jx, last_jy);
4004 #else
4005     else
4006       DrawLevelField(last_jx, last_jy);
4007 #endif
4008
4009     if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
4010       DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4011   }
4012
4013   if (!IN_SCR_FIELD(sx, sy))
4014     return;
4015
4016   /* ----------------------------------------------------------------------- */
4017   /* draw things behind the player, if needed                                */
4018   /* ----------------------------------------------------------------------- */
4019
4020   if (Back[jx][jy])
4021     DrawLevelElement(jx, jy, Back[jx][jy]);
4022   else if (IS_ACTIVE_BOMB(element))
4023     DrawLevelElement(jx, jy, EL_EMPTY);
4024   else
4025   {
4026     if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
4027     {
4028       int old_element = GfxElement[jx][jy];
4029       int old_graphic = el_act_dir2img(old_element, action, move_dir);
4030       int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
4031
4032       if (GFX_CRUMBLED(old_element))
4033         DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
4034       else
4035         DrawGraphic(sx, sy, old_graphic, frame);
4036
4037       if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
4038         player_is_opaque = TRUE;
4039     }
4040     else
4041     {
4042       GfxElement[jx][jy] = EL_UNDEFINED;
4043
4044       /* make sure that pushed elements are drawn with correct frame rate */
4045 #if 1
4046       graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4047
4048       if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
4049         GfxFrame[jx][jy] = player->StepFrame;
4050 #else
4051       if (player->is_pushing && player->is_moving)
4052         GfxFrame[jx][jy] = player->StepFrame;
4053 #endif
4054
4055       DrawLevelField(jx, jy);
4056     }
4057   }
4058
4059 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
4060   /* ----------------------------------------------------------------------- */
4061   /* draw player himself                                                     */
4062   /* ----------------------------------------------------------------------- */
4063
4064   graphic = getPlayerGraphic(player, move_dir);
4065
4066   /* in the case of changed player action or direction, prevent the current
4067      animation frame from being restarted for identical animations */
4068   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4069     player->Frame = last_player_frame;
4070
4071   frame = getGraphicAnimationFrame(graphic, player->Frame);
4072
4073   if (player->GfxPos)
4074   {
4075     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4076       sxx = player->GfxPos;
4077     else
4078       syy = player->GfxPos;
4079   }
4080
4081   if (!setup.soft_scrolling && ScreenMovPos)
4082     sxx = syy = 0;
4083
4084   if (player_is_opaque)
4085     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4086   else
4087     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4088
4089   if (SHIELD_ON(player))
4090   {
4091     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4092                    IMG_SHIELD_NORMAL_ACTIVE);
4093     int frame = getGraphicAnimationFrame(graphic, -1);
4094
4095     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4096   }
4097 #endif
4098
4099 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4100   if (player->GfxPos)
4101   {
4102     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4103       sxx = player->GfxPos;
4104     else
4105       syy = player->GfxPos;
4106   }
4107 #endif
4108
4109   /* ----------------------------------------------------------------------- */
4110   /* draw things the player is pushing, if needed                            */
4111   /* ----------------------------------------------------------------------- */
4112
4113 #if 0
4114   printf("::: %d, %d [%d, %d] [%d]\n",
4115          player->is_pushing, player_is_moving, player->GfxAction,
4116          player->is_moving, player_is_moving);
4117 #endif
4118
4119 #if 1
4120   if (player->is_pushing && player->is_moving)
4121   {
4122     int px = SCREENX(jx), py = SCREENY(jy);
4123     int pxx = (TILEX - ABS(sxx)) * dx;
4124     int pyy = (TILEY - ABS(syy)) * dy;
4125     int gfx_frame = GfxFrame[jx][jy];
4126
4127     int graphic;
4128     int sync_frame;
4129     int frame;
4130
4131     if (!IS_MOVING(jx, jy))             /* push movement already finished */
4132     {
4133       element = Feld[next_jx][next_jy];
4134       gfx_frame = GfxFrame[next_jx][next_jy];
4135     }
4136
4137     graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
4138
4139 #if 1
4140     sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
4141     frame = getGraphicAnimationFrame(graphic, sync_frame);
4142 #else
4143     frame = getGraphicAnimationFrame(graphic, player->StepFrame);
4144 #endif
4145
4146     /* draw background element under pushed element (like the Sokoban field) */
4147 #if 1
4148     if (game.use_masked_pushing && IS_MOVING(jx, jy))
4149     {
4150       /* this allows transparent pushing animation over non-black background */
4151
4152       if (Back[jx][jy])
4153         DrawLevelElement(jx, jy, Back[jx][jy]);
4154       else
4155         DrawLevelElement(jx, jy, EL_EMPTY);
4156
4157       if (Back[next_jx][next_jy])
4158         DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4159       else
4160         DrawLevelElement(next_jx, next_jy, EL_EMPTY);
4161     }
4162     else if (Back[next_jx][next_jy])
4163       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4164 #else
4165     if (Back[next_jx][next_jy])
4166       DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
4167 #endif
4168
4169 #if 0
4170     printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
4171            jx, px, player->GfxPos, player->StepFrame,
4172            player->is_pushing,
4173            dx, sxx, pxx,
4174            IS_MOVING(jx, jy),
4175            graphic, frame,
4176            GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
4177 #endif
4178
4179 #if 1
4180     /* do not draw (EM style) pushing animation when pushing is finished */
4181     /* (two-tile animations usually do not contain start and end frame) */
4182     if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
4183       DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
4184     else
4185       DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4186 #else
4187     /* masked drawing is needed for EMC style (double) movement graphics */
4188     /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
4189     DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
4190 #endif
4191   }
4192 #endif
4193
4194 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
4195   /* ----------------------------------------------------------------------- */
4196   /* draw player himself                                                     */
4197   /* ----------------------------------------------------------------------- */
4198
4199   graphic = getPlayerGraphic(player, move_dir);
4200
4201   /* in the case of changed player action or direction, prevent the current
4202      animation frame from being restarted for identical animations */
4203   if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
4204     player->Frame = last_player_frame;
4205
4206   frame = getGraphicAnimationFrame(graphic, player->Frame);
4207
4208   if (player->GfxPos)
4209   {
4210     if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4211       sxx = player->GfxPos;
4212     else
4213       syy = player->GfxPos;
4214   }
4215
4216   if (!setup.soft_scrolling && ScreenMovPos)
4217     sxx = syy = 0;
4218
4219   if (player_is_opaque)
4220     DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4221   else
4222     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4223
4224   if (SHIELD_ON(player))
4225   {
4226     int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4227                    IMG_SHIELD_NORMAL_ACTIVE);
4228     int frame = getGraphicAnimationFrame(graphic, -1);
4229
4230     DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4231   }
4232 #endif
4233
4234   /* ----------------------------------------------------------------------- */
4235   /* draw things in front of player (active dynamite or dynabombs)           */
4236   /* ----------------------------------------------------------------------- */
4237
4238   if (IS_ACTIVE_BOMB(element))
4239   {
4240     graphic = el2img(element);
4241     frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4242
4243     if (game.emulation == EMU_SUPAPLEX)
4244       DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4245     else
4246       DrawGraphicThruMask(sx, sy, graphic, frame);
4247   }
4248
4249   if (player_is_moving && last_element == EL_EXPLOSION)
4250   {
4251     int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4252                    GfxElement[last_jx][last_jy] :  EL_EMPTY);
4253     int graphic = el_act2img(element, ACTION_EXPLODING);
4254     int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4255     int phase = ExplodePhase[last_jx][last_jy] - 1;
4256     int frame = getGraphicAnimationFrame(graphic, phase - delay);
4257
4258     if (phase >= delay)
4259       DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4260   }
4261
4262   /* ----------------------------------------------------------------------- */
4263   /* draw elements the player is just walking/passing through/under          */
4264   /* ----------------------------------------------------------------------- */
4265
4266   if (player_is_moving)
4267   {
4268     /* handle the field the player is leaving ... */
4269     if (IS_ACCESSIBLE_INSIDE(last_element))
4270       DrawLevelField(last_jx, last_jy);
4271     else if (IS_ACCESSIBLE_UNDER(last_element))
4272       DrawLevelFieldThruMask(last_jx, last_jy);
4273   }
4274
4275   /* do not redraw accessible elements if the player is just pushing them */
4276   if (!player_is_moving || !player->is_pushing)
4277   {
4278     /* ... and the field the player is entering */
4279     if (IS_ACCESSIBLE_INSIDE(element))
4280       DrawLevelField(jx, jy);
4281     else if (IS_ACCESSIBLE_UNDER(element))
4282       DrawLevelFieldThruMask(jx, jy);
4283   }
4284
4285   MarkTileDirty(sx, sy);
4286 }
4287
4288 /* ------------------------------------------------------------------------- */
4289
4290 void WaitForEventToContinue()
4291 {
4292   boolean still_wait = TRUE;
4293
4294   /* simulate releasing mouse button over last gadget, if still pressed */
4295   if (button_status)
4296     HandleGadgets(-1, -1, 0);
4297
4298   button_status = MB_RELEASED;
4299
4300 #if 1
4301   ClearEventQueue();
4302 #endif
4303
4304   while (still_wait)
4305   {
4306     if (PendingEvent())
4307     {
4308       Event event;
4309
4310       NextEvent(&event);
4311
4312       switch (event.type)
4313       {
4314         case EVENT_BUTTONPRESS:
4315         case EVENT_KEYPRESS:
4316           still_wait = FALSE;
4317           break;
4318
4319         case EVENT_KEYRELEASE:
4320           ClearPlayerAction();
4321           break;
4322
4323         default:
4324           HandleOtherEvents(&event);
4325           break;
4326       }
4327     }
4328     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4329     {
4330       still_wait = FALSE;
4331     }
4332
4333     DoAnimation();
4334
4335     /* don't eat all CPU time */
4336     Delay(10);
4337   }
4338 }
4339
4340 #define MAX_REQUEST_LINES               13
4341 #define MAX_REQUEST_LINE_FONT1_LEN      7
4342 #define MAX_REQUEST_LINE_FONT2_LEN      10
4343
4344 #if 1
4345
4346 static int RequestHandleEvents(unsigned int req_state)
4347 {
4348   int last_game_status = game_status;   /* save current game status */
4349   int result;
4350   int mx, my;
4351
4352   button_status = MB_RELEASED;
4353
4354   request_gadget_id = -1;
4355   result = -1;
4356
4357   while (result < 0)
4358   {
4359     if (PendingEvent())
4360     {
4361       Event event;
4362
4363       NextEvent(&event);
4364
4365       switch (event.type)
4366       {
4367         case EVENT_BUTTONPRESS:
4368         case EVENT_BUTTONRELEASE:
4369         case EVENT_MOTIONNOTIFY:
4370         {
4371           if (event.type == EVENT_MOTIONNOTIFY)
4372           {
4373             if (!PointerInWindow(window))
4374               continue; /* window and pointer are on different screens */
4375
4376             if (!button_status)
4377               continue;
4378
4379             motion_status = TRUE;
4380             mx = ((MotionEvent *) &event)->x;
4381             my = ((MotionEvent *) &event)->y;
4382           }
4383           else
4384           {
4385             motion_status = FALSE;
4386             mx = ((ButtonEvent *) &event)->x;
4387             my = ((ButtonEvent *) &event)->y;
4388             if (event.type == EVENT_BUTTONPRESS)
4389               button_status = ((ButtonEvent *) &event)->button;
4390             else
4391               button_status = MB_RELEASED;
4392           }
4393
4394           /* this sets 'request_gadget_id' */
4395           HandleGadgets(mx, my, button_status);
4396
4397           switch (request_gadget_id)
4398           {
4399             case TOOL_CTRL_ID_YES:
4400               result = TRUE;
4401               break;
4402             case TOOL_CTRL_ID_NO:
4403               result = FALSE;
4404               break;
4405             case TOOL_CTRL_ID_CONFIRM:
4406               result = TRUE | FALSE;
4407               break;
4408
4409             case TOOL_CTRL_ID_PLAYER_1:
4410               result = 1;
4411               break;
4412             case TOOL_CTRL_ID_PLAYER_2:
4413               result = 2;
4414               break;
4415             case TOOL_CTRL_ID_PLAYER_3:
4416               result = 3;
4417               break;
4418             case TOOL_CTRL_ID_PLAYER_4:
4419               result = 4;
4420               break;
4421
4422             default:
4423               break;
4424           }
4425
4426           break;
4427         }
4428
4429         case EVENT_KEYPRESS:
4430           switch (GetEventKey((KeyEvent *)&event, TRUE))
4431           {
4432             case KSYM_space:
4433               if (req_state & REQ_CONFIRM)
4434                 result = 1;
4435               break;
4436
4437             case KSYM_Return:
4438               result = 1;
4439               break;
4440
4441             case KSYM_Escape:
4442 #if defined(TARGET_SDL2)
4443             case KSYM_Back:
4444 #endif
4445               result = 0;
4446               break;
4447
4448             default:
4449               break;
4450           }
4451
4452           if (req_state & REQ_PLAYER)
4453             result = 0;
4454           break;
4455
4456         case EVENT_KEYRELEASE:
4457           ClearPlayerAction();
4458           break;
4459
4460         default:
4461           HandleOtherEvents(&event);
4462           break;
4463       }
4464     }
4465     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4466     {
4467       int joy = AnyJoystick();
4468
4469       if (joy & JOY_BUTTON_1)
4470         result = 1;
4471       else if (joy & JOY_BUTTON_2)
4472         result = 0;
4473     }
4474
4475 #if 1
4476
4477     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4478     {
4479       HandleGameActions();
4480     }
4481     else
4482     {
4483       DoAnimation();
4484
4485       if (!PendingEvent())      /* delay only if no pending events */
4486         Delay(10);
4487     }
4488
4489 #if 1
4490     game_status = GAME_MODE_PSEUDO_DOOR;
4491 #endif
4492
4493     BackToFront();
4494
4495 #if 1
4496     game_status = last_game_status;     /* restore current game status */
4497 #endif
4498
4499 #else
4500
4501     DoAnimation();
4502
4503 #if 1
4504     if (!PendingEvent())        /* delay only if no pending events */
4505       Delay(10);
4506 #else
4507     /* don't eat all CPU time */
4508     Delay(10);
4509 #endif
4510
4511 #endif
4512   }
4513
4514   return result;
4515 }
4516
4517 static boolean RequestDoor(char *text, unsigned int req_state)
4518 {
4519   unsigned int old_door_state;
4520   int last_game_status = game_status;   /* save current game status */
4521   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4522   int font_nr = FONT_TEXT_2;
4523   char *text_ptr;
4524   int result;
4525   int ty;
4526
4527   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4528   {
4529     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4530     font_nr = FONT_TEXT_1;
4531   }
4532
4533   if (game_status == GAME_MODE_PLAYING)
4534   {
4535     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4536       BlitScreenToBitmap_EM(backbuffer);
4537     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4538       BlitScreenToBitmap_SP(backbuffer);
4539   }
4540
4541   /* disable deactivated drawing when quick-loading level tape recording */
4542   if (tape.playing && tape.deactivate_display)
4543     TapeDeactivateDisplayOff(TRUE);
4544
4545   SetMouseCursor(CURSOR_DEFAULT);
4546
4547 #if defined(NETWORK_AVALIABLE)
4548   /* pause network game while waiting for request to answer */
4549   if (options.network &&
4550       game_status == GAME_MODE_PLAYING &&
4551       req_state & REQUEST_WAIT_FOR_INPUT)
4552     SendToServer_PausePlaying();
4553 #endif
4554
4555   old_door_state = GetDoorState();
4556
4557   /* simulate releasing mouse button over last gadget, if still pressed */
4558   if (button_status)
4559     HandleGadgets(-1, -1, 0);
4560
4561   UnmapAllGadgets();
4562
4563   /* draw released gadget before proceeding */
4564   // BackToFront();
4565
4566   if (old_door_state & DOOR_OPEN_1)
4567   {
4568     CloseDoor(DOOR_CLOSE_1);
4569
4570     /* save old door content */
4571 #if 1
4572     BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
4573                0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
4574 #else
4575     BlitBitmap(bitmap_db_door, bitmap_db_door,
4576                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4577                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4578 #endif
4579   }
4580
4581   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4582   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4583
4584   /* clear door drawing field */
4585   DrawBackground(DX, DY, DXSIZE, DYSIZE);
4586
4587   /* force DOOR font inside door area */
4588   game_status = GAME_MODE_PSEUDO_DOOR;
4589
4590   /* write text for request */
4591   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4592   {
4593     char text_line[max_request_line_len + 1];
4594     int tx, tl, tc = 0;
4595
4596     if (!*text_ptr)
4597       break;
4598
4599     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4600     {
4601       tc = *(text_ptr + tx);
4602       // if (!tc || tc == ' ')
4603       if (!tc || tc == ' ' || tc == '?' || tc == '!')
4604         break;
4605     }
4606
4607     if ((tc == '?' || tc == '!') && tl == 0)
4608       tl = 1;
4609
4610     if (!tl)
4611     { 
4612       text_ptr++; 
4613       ty--; 
4614       continue; 
4615     }
4616
4617     strncpy(text_line, text_ptr, tl);
4618     text_line[tl] = 0;
4619
4620     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4621              DY + 8 + ty * (getFontHeight(font_nr) + 2),
4622              text_line, font_nr);
4623
4624     text_ptr += tl + (tc == ' ' ? 1 : 0);
4625     // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
4626   }
4627
4628   game_status = last_game_status;       /* restore current game status */
4629
4630   if (req_state & REQ_ASK)
4631   {
4632     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4633     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4634   }
4635   else if (req_state & REQ_CONFIRM)
4636   {
4637     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4638   }
4639   else if (req_state & REQ_PLAYER)
4640   {
4641     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4642     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4643     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4644     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4645   }
4646
4647   /* copy request gadgets to door backbuffer */
4648 #if 1
4649   BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
4650 #else
4651   BlitBitmap(drawto, bitmap_db_door,
4652              DX, DY, DXSIZE, DYSIZE,
4653              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4654 #endif
4655
4656   OpenDoor(DOOR_OPEN_1);
4657
4658   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4659   {
4660     if (game_status == GAME_MODE_PLAYING)
4661     {
4662       SetPanelBackground();
4663       SetDrawBackgroundMask(REDRAW_DOOR_1);
4664     }
4665     else
4666     {
4667       SetDrawBackgroundMask(REDRAW_FIELD);
4668     }
4669
4670     return FALSE;
4671   }
4672
4673   if (game_status != GAME_MODE_MAIN)
4674     InitAnimation();
4675
4676   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4677
4678   // ---------- handle request buttons ----------
4679   result = RequestHandleEvents(req_state);
4680
4681   if (game_status != GAME_MODE_MAIN)
4682     StopAnimation();
4683
4684   UnmapToolButtons();
4685
4686   if (!(req_state & REQ_STAY_OPEN))
4687   {
4688     CloseDoor(DOOR_CLOSE_1);
4689
4690     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4691         (req_state & REQ_REOPEN))
4692       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4693   }
4694
4695   RemapAllGadgets();
4696
4697   if (game_status == GAME_MODE_PLAYING)
4698   {
4699     SetPanelBackground();
4700     SetDrawBackgroundMask(REDRAW_DOOR_1);
4701   }
4702   else
4703   {
4704     SetDrawBackgroundMask(REDRAW_FIELD);
4705   }
4706
4707 #if defined(NETWORK_AVALIABLE)
4708   /* continue network game after request */
4709   if (options.network &&
4710       game_status == GAME_MODE_PLAYING &&
4711       req_state & REQUEST_WAIT_FOR_INPUT)
4712     SendToServer_ContinuePlaying();
4713 #endif
4714
4715   /* restore deactivated drawing when quick-loading level tape recording */
4716   if (tape.playing && tape.deactivate_display)
4717     TapeDeactivateDisplayOn();
4718
4719   return result;
4720 }
4721
4722 static boolean RequestEnvelope(char *text, unsigned int req_state)
4723 {
4724   int result;
4725 #if 0
4726   int i;
4727 #endif
4728
4729   if (game_status == GAME_MODE_PLAYING)
4730   {
4731     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4732       BlitScreenToBitmap_EM(backbuffer);
4733     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4734       BlitScreenToBitmap_SP(backbuffer);
4735   }
4736
4737   /* disable deactivated drawing when quick-loading level tape recording */
4738   if (tape.playing && tape.deactivate_display)
4739     TapeDeactivateDisplayOff(TRUE);
4740
4741   SetMouseCursor(CURSOR_DEFAULT);
4742
4743 #if defined(NETWORK_AVALIABLE)
4744   /* pause network game while waiting for request to answer */
4745   if (options.network &&
4746       game_status == GAME_MODE_PLAYING &&
4747       req_state & REQUEST_WAIT_FOR_INPUT)
4748     SendToServer_PausePlaying();
4749 #endif
4750
4751   /* simulate releasing mouse button over last gadget, if still pressed */
4752   if (button_status)
4753     HandleGadgets(-1, -1, 0);
4754
4755   UnmapAllGadgets();
4756
4757   // (replace with setting corresponding request background)
4758   // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4759   // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4760
4761   /* clear door drawing field */
4762   // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4763
4764 #if 0
4765   if (global.use_envelope_request)
4766   {
4767     /* !!! TMP !!! */
4768     FreeToolButtons();
4769     CreateToolButtons();
4770   }
4771 #endif
4772
4773 #if 0
4774 #if 0
4775   if (req_state & REQ_ASK)
4776   {
4777     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4778     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4779   }
4780   else if (req_state & REQ_CONFIRM)
4781   {
4782     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4783   }
4784   else if (req_state & REQ_PLAYER)
4785   {
4786     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4787     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4788     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4789     MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4790   }
4791 #else
4792   if (req_state & REQ_ASK)
4793   {
4794     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4795     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4796   }
4797   else if (req_state & REQ_CONFIRM)
4798   {
4799     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4800   }
4801   else if (req_state & REQ_PLAYER)
4802   {
4803     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4804     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4805     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4806     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4807   }
4808 #endif
4809 #endif
4810
4811   ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4812
4813 #if 0
4814   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4815   {
4816     if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4817                                  i == TOOL_CTRL_ID_NO)) ||
4818         (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4819         (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4820                                     i == TOOL_CTRL_ID_PLAYER_2 &&
4821                                     i == TOOL_CTRL_ID_PLAYER_3 &&
4822                                     i == TOOL_CTRL_ID_PLAYER_4)))
4823     {
4824       int x = tool_gadget[i]->x + dDX;
4825       int y = tool_gadget[i]->y + dDY;
4826
4827       ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4828     }
4829   }
4830 #endif
4831
4832   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4833   {
4834     if (game_status == GAME_MODE_PLAYING)
4835     {
4836       SetPanelBackground();
4837       SetDrawBackgroundMask(REDRAW_DOOR_1);
4838     }
4839     else
4840     {
4841       SetDrawBackgroundMask(REDRAW_FIELD);
4842     }
4843
4844     return FALSE;
4845   }
4846
4847 #if 0
4848   if (game_status != GAME_MODE_MAIN)
4849     InitAnimation();
4850 #endif
4851
4852   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4853
4854   // ---------- handle request buttons ----------
4855   result = RequestHandleEvents(req_state);
4856
4857   if (game_status != GAME_MODE_MAIN)
4858     StopAnimation();
4859
4860   UnmapToolButtons();
4861
4862   ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4863
4864   RemapAllGadgets();
4865
4866   if (game_status == GAME_MODE_PLAYING)
4867   {
4868     SetPanelBackground();
4869     SetDrawBackgroundMask(REDRAW_DOOR_1);
4870   }
4871   else
4872   {
4873     SetDrawBackgroundMask(REDRAW_FIELD);
4874   }
4875
4876 #if defined(NETWORK_AVALIABLE)
4877   /* continue network game after request */
4878   if (options.network &&
4879       game_status == GAME_MODE_PLAYING &&
4880       req_state & REQUEST_WAIT_FOR_INPUT)
4881     SendToServer_ContinuePlaying();
4882 #endif
4883
4884   /* restore deactivated drawing when quick-loading level tape recording */
4885   if (tape.playing && tape.deactivate_display)
4886     TapeDeactivateDisplayOn();
4887
4888   return result;
4889 }
4890
4891 boolean Request(char *text, unsigned int req_state)
4892 {
4893   if (global.use_envelope_request)
4894     return RequestEnvelope(text, req_state);
4895   else
4896     return RequestDoor(text, req_state);
4897 }
4898
4899 #else   // =====================================================================
4900
4901 boolean Request(char *text, unsigned int req_state)
4902 {
4903   int mx, my, ty, result = -1;
4904   unsigned int old_door_state;
4905   int last_game_status = game_status;   /* save current game status */
4906   int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4907   int font_nr = FONT_TEXT_2;
4908 #if 0
4909   int max_word_len = 0;
4910 #endif
4911   char *text_ptr;
4912   int i;
4913
4914 #if 0
4915   global.use_envelope_request = 1;
4916 #endif
4917
4918 #if 1
4919   if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4920   {
4921     max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4922     font_nr = FONT_TEXT_1;
4923   }
4924 #else
4925   for (text_ptr = text; *text_ptr; text_ptr++)
4926   {
4927     max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4928
4929     if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4930     {
4931       max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4932 #if 1
4933       font_nr = FONT_TEXT_1;
4934 #else
4935       font_nr = FONT_LEVEL_NUMBER;
4936 #endif
4937
4938       break;
4939     }
4940   }
4941 #endif
4942
4943   if (game_status == GAME_MODE_PLAYING)
4944   {
4945     if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4946       BlitScreenToBitmap_EM(backbuffer);
4947     else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4948       BlitScreenToBitmap_SP(backbuffer);
4949   }
4950
4951   /* disable deactivated drawing when quick-loading level tape recording */
4952   if (tape.playing && tape.deactivate_display)
4953     TapeDeactivateDisplayOff(TRUE);
4954
4955   SetMouseCursor(CURSOR_DEFAULT);
4956
4957 #if defined(NETWORK_AVALIABLE)
4958   /* pause network game while waiting for request to answer */
4959   if (options.network &&
4960       game_status == GAME_MODE_PLAYING &&
4961       req_state & REQUEST_WAIT_FOR_INPUT)
4962     SendToServer_PausePlaying();
4963 #endif
4964
4965   old_door_state = GetDoorState();
4966
4967   /* simulate releasing mouse button over last gadget, if still pressed */
4968   if (button_status)
4969     HandleGadgets(-1, -1, 0);
4970
4971   UnmapAllGadgets();
4972
4973   /* draw released gadget before proceeding */
4974   // BackToFront();
4975
4976 #if 0
4977   if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4978 #else
4979   if (old_door_state & DOOR_OPEN_1)
4980 #endif
4981   {
4982 #if 1
4983     if (!global.use_envelope_request)
4984       CloseDoor(DOOR_CLOSE_1);
4985 #else
4986     CloseDoor(DOOR_CLOSE_1);
4987 #endif
4988
4989     /* save old door content */
4990     BlitBitmap(bitmap_db_door, bitmap_db_door,
4991                DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4992                DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4993   }
4994
4995 #if 1
4996   SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4997 #endif
4998
4999   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5000
5001   /* clear door drawing field */
5002   DrawBackground(DX, DY, DXSIZE, DYSIZE);
5003
5004   /* force DOOR font inside door area */
5005   game_status = GAME_MODE_PSEUDO_DOOR;
5006
5007   /* write text for request */
5008   for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
5009   {
5010     char text_line[max_request_line_len + 1];
5011     int tx, tl, tc = 0;
5012
5013     if (!*text_ptr)
5014       break;
5015
5016     for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
5017     {
5018       tc = *(text_ptr + tx);
5019       if (!tc || tc == ' ')
5020         break;
5021     }
5022
5023     if (!tl)
5024     { 
5025       text_ptr++; 
5026       ty--; 
5027       continue; 
5028     }
5029
5030     strncpy(text_line, text_ptr, tl);
5031     text_line[tl] = 0;
5032
5033     DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
5034              DY + 8 + ty * (getFontHeight(font_nr) + 2),
5035              text_line, font_nr);
5036
5037     text_ptr += tl + (tc == ' ' ? 1 : 0);
5038   }
5039
5040   game_status = last_game_status;       /* restore current game status */
5041
5042 #if 1
5043   if (global.use_envelope_request)
5044   {
5045     /* !!! TMP !!! */
5046     FreeToolButtons();
5047     CreateToolButtons();
5048   }
5049 #endif
5050
5051   if (req_state & REQ_ASK)
5052   {
5053     MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
5054     MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
5055   }
5056   else if (req_state & REQ_CONFIRM)
5057   {
5058     MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
5059   }
5060   else if (req_state & REQ_PLAYER)
5061   {
5062     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
5063     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
5064     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
5065     MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
5066   }
5067
5068   /* copy request gadgets to door backbuffer */
5069   BlitBitmap(drawto, bitmap_db_door,
5070              DX, DY, DXSIZE, DYSIZE,
5071              DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5072
5073 #if 1
5074   if (global.use_envelope_request)
5075   {
5076     ShowEnvelopeRequest(text, ACTION_OPENING);
5077
5078     for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5079     {
5080       if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
5081                                    i == TOOL_CTRL_ID_NO)) ||
5082           (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
5083           (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
5084                                       i == TOOL_CTRL_ID_PLAYER_2 &&
5085                                       i == TOOL_CTRL_ID_PLAYER_3 &&
5086                                       i == TOOL_CTRL_ID_PLAYER_4)))
5087       {
5088         int x = tool_gadget[i]->x + dDX;
5089         int y = tool_gadget[i]->y + dDY;
5090
5091         ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
5092       }
5093     }
5094   }
5095 #endif
5096
5097 #if 1
5098   if (!global.use_envelope_request)
5099     OpenDoor(DOOR_OPEN_1);
5100 #else
5101   OpenDoor(DOOR_OPEN_1);
5102 #endif
5103
5104   if (!(req_state & REQUEST_WAIT_FOR_INPUT))
5105   {
5106     if (game_status == GAME_MODE_PLAYING)
5107     {
5108       SetPanelBackground();
5109       SetDrawBackgroundMask(REDRAW_DOOR_1);
5110     }
5111     else
5112     {
5113       SetDrawBackgroundMask(REDRAW_FIELD);
5114     }
5115
5116     return FALSE;
5117   }
5118
5119 #if 1
5120   if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
5121     InitAnimation();
5122 #else
5123   if (game_status != GAME_MODE_MAIN)
5124     InitAnimation();
5125 #endif
5126
5127   button_status = MB_RELEASED;
5128
5129   request_gadget_id = -1;
5130
5131   SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
5132
5133   while (result < 0)
5134   {
5135     if (PendingEvent())
5136     {
5137       Event event;
5138
5139       NextEvent(&event);
5140
5141       switch (event.type)
5142       {
5143         case EVENT_BUTTONPRESS:
5144         case EVENT_BUTTONRELEASE:
5145         case EVENT_MOTIONNOTIFY:
5146         {
5147           if (event.type == EVENT_MOTIONNOTIFY)
5148           {
5149             if (!PointerInWindow(window))
5150               continue; /* window and pointer are on different screens */
5151
5152             if (!button_status)
5153               continue;
5154
5155             motion_status = TRUE;
5156             mx = ((MotionEvent *) &event)->x;
5157             my = ((MotionEvent *) &event)->y;
5158           }
5159           else
5160           {
5161             motion_status = FALSE;
5162             mx = ((ButtonEvent *) &event)->x;
5163             my = ((ButtonEvent *) &event)->y;
5164             if (event.type == EVENT_BUTTONPRESS)
5165               button_status = ((ButtonEvent *) &event)->button;
5166             else
5167               button_status = MB_RELEASED;
5168           }
5169
5170           /* this sets 'request_gadget_id' */
5171           HandleGadgets(mx, my, button_status);
5172
5173           switch (request_gadget_id)
5174           {
5175             case TOOL_CTRL_ID_YES:
5176               result = TRUE;
5177               break;
5178             case TOOL_CTRL_ID_NO:
5179               result = FALSE;
5180               break;
5181             case TOOL_CTRL_ID_CONFIRM:
5182               result = TRUE | FALSE;
5183               break;
5184
5185             case TOOL_CTRL_ID_PLAYER_1:
5186               result = 1;
5187               break;
5188             case TOOL_CTRL_ID_PLAYER_2:
5189               result = 2;
5190               break;
5191             case TOOL_CTRL_ID_PLAYER_3:
5192               result = 3;
5193               break;
5194             case TOOL_CTRL_ID_PLAYER_4:
5195               result = 4;
5196               break;
5197
5198             default:
5199               break;
5200           }
5201
5202           break;
5203         }
5204
5205         case EVENT_KEYPRESS:
5206           switch (GetEventKey((KeyEvent *)&event, TRUE))
5207           {
5208             case KSYM_space:
5209               if (req_state & REQ_CONFIRM)
5210                 result = 1;
5211               break;
5212
5213             case KSYM_Return:
5214               result = 1;
5215               break;
5216
5217             case KSYM_Escape:
5218 #if defined(TARGET_SDL2)
5219             case KSYM_Back:
5220 #endif
5221               result = 0;
5222               break;
5223
5224             default:
5225               break;
5226           }
5227
5228           if (req_state & REQ_PLAYER)
5229             result = 0;
5230           break;
5231
5232         case EVENT_KEYRELEASE:
5233           ClearPlayerAction();
5234           break;
5235
5236         default:
5237           HandleOtherEvents(&event);
5238           break;
5239       }
5240     }
5241     else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5242     {
5243       int joy = AnyJoystick();
5244
5245       if (joy & JOY_BUTTON_1)
5246         result = 1;
5247       else if (joy & JOY_BUTTON_2)
5248         result = 0;
5249     }
5250
5251 #if 1
5252
5253     if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5254     {
5255       HandleGameActions();
5256     }
5257     else
5258     {
5259       DoAnimation();
5260
5261       if (!PendingEvent())      /* delay only if no pending events */
5262         Delay(10);
5263     }
5264
5265 #if 1
5266     game_status = GAME_MODE_PSEUDO_DOOR;
5267 #endif
5268
5269     BackToFront();
5270
5271 #if 1
5272     game_status = last_game_status;     /* restore current game status */
5273 #endif
5274
5275 #else
5276
5277     DoAnimation();
5278
5279 #if 1
5280     if (!PendingEvent())        /* delay only if no pending events */
5281       Delay(10);
5282 #else
5283     /* don't eat all CPU time */
5284     Delay(10);
5285 #endif
5286
5287 #endif
5288   }
5289
5290   if (game_status != GAME_MODE_MAIN)
5291     StopAnimation();
5292
5293   UnmapToolButtons();
5294
5295 #if 1
5296   if (global.use_envelope_request)
5297     ShowEnvelopeRequest(text, ACTION_CLOSING);
5298 #endif
5299
5300 #if 1
5301   if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5302 #else
5303   if (!(req_state & REQ_STAY_OPEN))
5304 #endif
5305   {
5306     CloseDoor(DOOR_CLOSE_1);
5307
5308     if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5309         (req_state & REQ_REOPEN))
5310       OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5311   }
5312
5313   RemapAllGadgets();
5314
5315   if (game_status == GAME_MODE_PLAYING)
5316   {
5317     SetPanelBackground();
5318     SetDrawBackgroundMask(REDRAW_DOOR_1);
5319   }
5320   else
5321   {
5322     SetDrawBackgroundMask(REDRAW_FIELD);
5323   }
5324
5325 #if defined(NETWORK_AVALIABLE)
5326   /* continue network game after request */
5327   if (options.network &&
5328       game_status == GAME_MODE_PLAYING &&
5329       req_state & REQUEST_WAIT_FOR_INPUT)
5330     SendToServer_ContinuePlaying();
5331 #endif
5332
5333   /* restore deactivated drawing when quick-loading level tape recording */
5334   if (tape.playing && tape.deactivate_display)
5335     TapeDeactivateDisplayOn();
5336
5337   return result;
5338 }
5339
5340 #endif
5341
5342 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
5343 {
5344   const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
5345   const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
5346   int compare_result;
5347
5348   if (dpo1->sort_priority != dpo2->sort_priority)
5349     compare_result = dpo1->sort_priority - dpo2->sort_priority;
5350   else
5351     compare_result = dpo1->nr - dpo2->nr;
5352
5353   return compare_result;
5354 }
5355
5356 void InitGraphicCompatibilityInfo_Doors()
5357 {
5358   struct
5359   {
5360     int door_token;
5361     int part_1, part_8;
5362     struct DoorInfo *door;
5363   }
5364   doors[] =
5365   {
5366     { DOOR_1,   IMG_DOOR_1_GFX_PART_1,  IMG_DOOR_1_GFX_PART_8,  &door_1 },
5367     { DOOR_2,   IMG_DOOR_2_GFX_PART_1,  IMG_DOOR_2_GFX_PART_8,  &door_2 },
5368
5369     { -1,       -1,                     -1,                     NULL    }
5370   };
5371   struct Rect door_rect_list[] =
5372   {
5373     { DX, DY, DXSIZE, DYSIZE },
5374     { VX, VY, VXSIZE, VYSIZE }
5375   };
5376   int i, j;
5377
5378   for (i = 0; doors[i].door_token != -1; i++)
5379   {
5380     int door_token = doors[i].door_token;
5381     int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5382     int part_1 = doors[i].part_1;
5383     int part_8 = doors[i].part_8;
5384     int part_2 = part_1 + 1;
5385     int part_3 = part_1 + 2;
5386     struct DoorInfo *door = doors[i].door;
5387     struct Rect *door_rect = &door_rect_list[door_index];
5388     boolean door_gfx_redefined = FALSE;
5389
5390     /* check if any door part graphic definitions have been redefined */
5391
5392     for (j = 0; door_part_controls[j].door_token != -1; j++)
5393     {
5394       struct DoorPartControlInfo *dpc = &door_part_controls[j];
5395       struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
5396
5397       if (dpc->door_token == door_token && fi->redefined)
5398         door_gfx_redefined = TRUE;
5399     }
5400
5401     /* check for old-style door graphic/animation modifications */
5402
5403     if (!door_gfx_redefined)
5404     {
5405       if (door->anim_mode & ANIM_STATIC_PANEL)
5406       {
5407         door->panel.step_xoffset = 0;
5408         door->panel.step_yoffset = 0;
5409       }
5410
5411       if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
5412       {
5413         struct GraphicInfo *g_part_1 = &graphic_info[part_1];
5414         struct GraphicInfo *g_part_2 = &graphic_info[part_2];
5415         int num_door_steps, num_panel_steps;
5416
5417         /* remove door part graphics other than the two default wings */
5418
5419         for (j = 0; door_part_controls[j].door_token != -1; j++)
5420         {
5421           struct DoorPartControlInfo *dpc = &door_part_controls[j];
5422           struct GraphicInfo *g = &graphic_info[dpc->graphic];
5423
5424           if (dpc->graphic >= part_3 &&
5425               dpc->graphic <= part_8)
5426             g->bitmap = NULL;
5427         }
5428
5429         /* set graphics and screen positions of the default wings */
5430
5431         g_part_1->width  = door_rect->width;
5432         g_part_1->height = door_rect->height;
5433         g_part_2->width  = door_rect->width;
5434         g_part_2->height = door_rect->height;
5435         g_part_2->src_x = door_rect->width;
5436         g_part_2->src_y = g_part_1->src_y;
5437
5438         door->part_2.x = door->part_1.x;
5439         door->part_2.y = door->part_1.y;
5440
5441         if (door->width != -1)
5442         {
5443           g_part_1->width = door->width;
5444           g_part_2->width = door->width;
5445
5446           // special treatment for graphics and screen position of right wing
5447           g_part_2->src_x += door_rect->width - door->width;
5448           door->part_2.x  += door_rect->width - door->width;
5449         }
5450
5451         if (door->height != -1)
5452         {
5453           g_part_1->height = door->height;
5454           g_part_2->height = door->height;
5455
5456           // special treatment for graphics and screen position of bottom wing
5457           g_part_2->src_y += door_rect->height - door->height;
5458           door->part_2.y  += door_rect->height - door->height;
5459         }
5460
5461         /* set animation delays for the default wings and panels */
5462
5463         door->part_1.step_delay = door->step_delay;
5464         door->part_2.step_delay = door->step_delay;
5465         door->panel.step_delay  = door->step_delay;
5466
5467         /* set animation draw order for the default wings */
5468
5469         door->part_1.sort_priority = 2; /* draw left wing over ... */
5470         door->part_2.sort_priority = 1; /*          ... right wing */
5471
5472         /* set animation draw offset for the default wings */
5473
5474         if (door->anim_mode & ANIM_HORIZONTAL)
5475         {
5476           door->part_1.step_xoffset = door->step_offset;
5477           door->part_1.step_yoffset = 0;
5478           door->part_2.step_xoffset = door->step_offset * -1;
5479           door->part_2.step_yoffset = 0;
5480
5481           num_door_steps = g_part_1->width / door->step_offset;
5482         }
5483         else    // ANIM_VERTICAL
5484         {
5485           door->part_1.step_xoffset = 0;
5486           door->part_1.step_yoffset = door->step_offset;
5487           door->part_2.step_xoffset = 0;
5488           door->part_2.step_yoffset = door->step_offset * -1;
5489
5490           num_door_steps = g_part_1->height / door->step_offset;
5491         }
5492
5493         /* set animation draw offset for the default panels */
5494
5495         if (door->step_offset > 1)
5496         {
5497           num_panel_steps = 2 * door_rect->height / door->step_offset;
5498           door->panel.start_step = num_panel_steps - num_door_steps;
5499         }
5500         else
5501         {
5502           num_panel_steps = door_rect->height / door->step_offset;
5503           door->panel.start_step = num_panel_steps - num_door_steps / 2;
5504           door->panel.step_delay *= 2;
5505         }
5506       }
5507     }
5508   }
5509 }
5510
5511 void InitDoors()
5512 {
5513   int i;
5514
5515   for (i = 0; door_part_controls[i].door_token != -1; i++)
5516   {
5517     struct DoorPartControlInfo *dpc = &door_part_controls[i];
5518     struct DoorPartOrderInfo *dpo = &door_part_order[i];
5519
5520     /* initialize "start_step_opening" and "start_step_closing", if needed */
5521     if (dpc->pos->start_step_opening == 0 &&
5522         dpc->pos->start_step_closing == 0)
5523     {
5524       // dpc->pos->start_step_opening = dpc->pos->start_step;
5525       dpc->pos->start_step_closing = dpc->pos->start_step;
5526     }
5527
5528     /* fill structure for door part draw order (sorted below) */
5529     dpo->nr = i;
5530     dpo->sort_priority = dpc->pos->sort_priority;
5531
5532 #if 0
5533     struct DoorPartPosInfo *pos = dpc->pos;
5534
5535     printf(":0: step_xoffset == %d, step_yoffset == %d\n",
5536            pos->step_xoffset, pos->step_yoffset);
5537 #endif
5538   }
5539
5540   /* sort door part controls according to sort_priority and graphic number */
5541   qsort(door_part_order, MAX_DOOR_PARTS,
5542         sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
5543 }
5544
5545 unsigned int OpenDoor(unsigned int door_state)
5546 {
5547   if (door_state & DOOR_COPY_BACK)
5548   {
5549 #if 1
5550     if (door_state & DOOR_OPEN_1)
5551       BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
5552                  1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
5553
5554     if (door_state & DOOR_OPEN_2)
5555       BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
5556                  1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
5557 #else
5558     if (door_state & DOOR_OPEN_1)
5559       BlitBitmap(bitmap_db_door, bitmap_db_door,
5560                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5561                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5562
5563     if (door_state & DOOR_OPEN_2)
5564       BlitBitmap(bitmap_db_door, bitmap_db_door,
5565                  DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5566                  DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5567 #endif
5568
5569     door_state &= ~DOOR_COPY_BACK;
5570   }
5571
5572   return MoveDoor(door_state);
5573 }
5574
5575 unsigned int CloseDoor(unsigned int door_state)
5576 {
5577   unsigned int old_door_state = GetDoorState();
5578
5579   if (!(door_state & DOOR_NO_COPY_BACK))
5580   {
5581 #if 1
5582     if (old_door_state & DOOR_OPEN_1)
5583       BlitBitmap(backbuffer, bitmap_db_door_1,
5584                  DX, DY, DXSIZE, DYSIZE, 0, 0);
5585
5586     if (old_door_state & DOOR_OPEN_2)
5587       BlitBitmap(backbuffer, bitmap_db_door_2,
5588                  VX, VY, VXSIZE, VYSIZE, 0, 0);
5589 #else
5590     if (old_door_state & DOOR_OPEN_1)
5591       BlitBitmap(backbuffer, bitmap_db_door,
5592                  DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5593
5594     if (old_door_state & DOOR_OPEN_2)
5595       BlitBitmap(backbuffer, bitmap_db_door,
5596                  VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5597 #endif
5598
5599     door_state &= ~DOOR_NO_COPY_BACK;
5600   }
5601
5602   return MoveDoor(door_state);
5603 }
5604
5605 unsigned int GetDoorState()
5606 {
5607   return MoveDoor(DOOR_GET_STATE);
5608 }
5609
5610 unsigned int SetDoorState(unsigned int door_state)
5611 {
5612   return MoveDoor(door_state | DOOR_SET_STATE);
5613 }
5614
5615 #if 1
5616
5617 // ========== TEST 1 ===========================================================
5618
5619 int euclid(int a, int b)
5620 {
5621   return (b ? euclid(b, a % b) : a);
5622 }
5623
5624 unsigned int MoveDoor(unsigned int door_state)
5625 {
5626 #if 0
5627   struct XY panel_pos_list[] =
5628   {
5629     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 },
5630     { DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 },
5631   };
5632 #endif
5633   struct Rect door_rect_list[] =
5634   {
5635     { DX, DY, DXSIZE, DYSIZE },
5636     { VX, VY, VXSIZE, VYSIZE }
5637   };
5638   static int door1 = DOOR_OPEN_1;
5639   static int door2 = DOOR_CLOSE_2;
5640   unsigned int door_delay = 0;
5641   unsigned int door_delay_value;
5642   int i;
5643
5644 #if 1
5645   if (door_1.width < 0 || door_1.width > DXSIZE)
5646     door_1.width = DXSIZE;
5647   if (door_1.height < 0 || door_1.height > DYSIZE)
5648     door_1.height = DYSIZE;
5649   if (door_2.width < 0 || door_2.width > VXSIZE)
5650     door_2.width = VXSIZE;
5651   if (door_2.height < 0 || door_2.height > VYSIZE)
5652     door_2.height = VYSIZE;
5653 #endif
5654
5655   if (door_state == DOOR_GET_STATE)
5656     return (door1 | door2);
5657
5658   if (door_state & DOOR_SET_STATE)
5659   {
5660     if (door_state & DOOR_ACTION_1)
5661       door1 = door_state & DOOR_ACTION_1;
5662     if (door_state & DOOR_ACTION_2)
5663       door2 = door_state & DOOR_ACTION_2;
5664
5665     return (door1 | door2);
5666   }
5667
5668   if (!(door_state & DOOR_FORCE_REDRAW))
5669   {
5670     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5671       door_state &= ~DOOR_OPEN_1;
5672     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5673       door_state &= ~DOOR_CLOSE_1;
5674     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5675       door_state &= ~DOOR_OPEN_2;
5676     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5677       door_state &= ~DOOR_CLOSE_2;
5678   }
5679
5680 #if 0
5681   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5682                       door_2.step_delay);
5683
5684   if (setup.quick_doors)
5685   {
5686     stepsize = 20;              /* must be chosen to always draw last frame */
5687     door_delay_value = 0;
5688   }
5689 #endif
5690
5691   if (global.autoplay_leveldir)
5692   {
5693     door_state |= DOOR_NO_DELAY;
5694     door_state &= ~DOOR_CLOSE_ALL;
5695   }
5696
5697 #if 1
5698   if (game_status == GAME_MODE_EDITOR)
5699     door_state |= DOOR_NO_DELAY;
5700 #endif
5701
5702   if (door_state & DOOR_ACTION)
5703   {
5704     boolean door_panel_drawn[NUM_DOORS];
5705     boolean panel_has_doors[NUM_DOORS];
5706     boolean door_part_skip[MAX_DOOR_PARTS];
5707     boolean door_part_done[MAX_DOOR_PARTS];
5708     boolean door_part_done_all;
5709     int num_steps[MAX_DOOR_PARTS];
5710     int max_move_delay = 0;     // delay for complete animations of all doors
5711     int max_step_delay = 0;     // delay (ms) between two animation frames
5712     int num_move_steps = 0;     // number of animation steps for all doors
5713     int current_move_delay = 0;
5714     int k;
5715
5716     for (i = 0; i < NUM_DOORS; i++)
5717       panel_has_doors[i] = FALSE;
5718
5719     for (i = 0; i < MAX_DOOR_PARTS; i++)
5720     {
5721       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5722       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5723       int door_token = dpc->door_token;
5724
5725       door_part_done[i] = FALSE;
5726       door_part_skip[i] = (!(door_state & door_token) ||
5727                            !g->bitmap);
5728     }
5729
5730 #if 0
5731     for (i = 0; i < MAX_DOOR_PARTS; i++)
5732     {
5733       struct DoorPartControlInfo *dpc = &door_part_controls[i];
5734       struct DoorPartPosInfo *pos = dpc->pos;
5735       int start_step = pos->start_step;
5736
5737       printf("::: ---> %d: start_step == %d [%d]\n",
5738              i, start_step, door_part_done[i]);
5739     }
5740 #endif
5741
5742     for (i = 0; i < MAX_DOOR_PARTS; i++)
5743     {
5744       int nr = door_part_order[i].nr;
5745       struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5746       struct DoorPartPosInfo *pos = dpc->pos;
5747       struct GraphicInfo *g = &graphic_info[dpc->graphic];
5748       int door_token = dpc->door_token;
5749       int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5750       boolean is_panel = DOOR_PART_IS_PANEL(nr);
5751       int step_xoffset = ABS(pos->step_xoffset);
5752       int step_yoffset = ABS(pos->step_yoffset);
5753       int step_delay = pos->step_delay;
5754       int current_door_state = door_state & door_token;
5755       boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5756       boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
5757       boolean part_opening = (is_panel ? door_closing : door_opening);
5758       int start_step = (part_opening ? pos->start_step_opening :
5759                         pos->start_step_closing);
5760       float move_xsize = (step_xoffset ? g->width  : 0);
5761       float move_ysize = (step_yoffset ? g->height : 0);
5762       int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
5763       int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
5764       int move_steps = (move_xsteps && move_ysteps ?
5765                         MIN(move_xsteps, move_ysteps) :
5766                         move_xsteps ? move_xsteps : move_ysteps) - start_step;
5767       int move_delay = move_steps * step_delay;
5768
5769       if (door_part_skip[nr])
5770         continue;
5771
5772       if (!is_panel)
5773         panel_has_doors[door_index] = TRUE;
5774
5775       max_move_delay = MAX(max_move_delay, move_delay);
5776       max_step_delay = (max_step_delay == 0 ? step_delay :
5777                         euclid(max_step_delay, step_delay));
5778       num_steps[nr] = move_steps;
5779
5780 #if 0
5781 #if 0
5782       printf("::: %d: move_delay == %d, start_step == %d [%d]\n",
5783              i, move_delay, start_step, door_part_order[i].nr);
5784 #else
5785       if (DOOR_PART_IS_PANEL(i))
5786         printf("::: %d: move_delay == %d, start_step == %d\n",
5787                i, move_delay, start_step);
5788 #endif
5789 #endif
5790     }
5791
5792     num_move_steps = max_move_delay / max_step_delay;
5793
5794     door_delay_value = max_step_delay;
5795
5796 #if 0
5797     door_delay_value *= 10;
5798 #endif
5799
5800 #if 0
5801     printf("::: num_move_steps == %d, max_move_delay == %d, max_step_delay == %d\n", num_move_steps, max_move_delay, max_step_delay);
5802 #endif
5803
5804     for (k = 0; k < num_move_steps; k++)
5805     {
5806       door_part_done_all = TRUE;
5807
5808       for (i = 0; i < NUM_DOORS; i++)
5809         door_panel_drawn[i] = FALSE;
5810
5811       for (i = 0; i < MAX_DOOR_PARTS; i++)
5812       {
5813         int nr = door_part_order[i].nr;
5814         struct DoorPartControlInfo *dpc = &door_part_controls[nr];
5815         struct DoorPartPosInfo *pos = dpc->pos;
5816         struct GraphicInfo *g = &graphic_info[dpc->graphic];
5817         int door_token = dpc->door_token;
5818         int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
5819         boolean is_panel = DOOR_PART_IS_PANEL(nr);
5820 #if 0
5821         struct XY *panel_pos = &panel_pos_list[door_index];
5822 #endif
5823         struct Rect *door_rect = &door_rect_list[door_index];
5824         Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
5825                                   bitmap_db_door_2);
5826         Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
5827         int current_door_state = door_state & door_token;
5828         boolean door_opening = ((current_door_state & DOOR_OPEN)  != 0);
5829         boolean door_closing = !door_opening;
5830         boolean part_opening = (is_panel ? door_closing : door_opening);
5831         boolean part_closing = !part_opening;
5832         int start_step = (part_opening ? pos->start_step_opening :
5833                           pos->start_step_closing);
5834         int step_delay = pos->step_delay;
5835         int step_factor = step_delay / max_step_delay;
5836         int k1 = (step_factor ? k / step_factor + 1 : k);
5837         int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
5838         int kk = (k2 < 0 ? 0 : k2);
5839         int src_x, src_y, src_xx, src_yy;
5840         int dst_x, dst_y, dst_xx, dst_yy;
5841         int width, height;
5842
5843 #if 0
5844         if (k == 0 && is_panel && door_token == DOOR_2)
5845           printf("::: %d, %d\n", g->width, g->height);
5846 #endif
5847
5848 #if 0
5849         if (DOOR_PART_IS_PANEL(nr))
5850         {
5851           int start_step = pos->start_step;
5852
5853           k2 = (door_closing ? k1 : num_steps[nr] - k1);// - start_step;
5854           kk = (k2 < 0 ? 0 : k2);
5855         }
5856 #endif
5857
5858 #if 0
5859         // !!! TEST !!! 
5860         if (nr != 16 && nr != 0)
5861           continue;
5862 #endif
5863
5864 #if 0
5865         // !!! TEST !!! 
5866         if (!is_panel)
5867           continue;
5868 #endif
5869
5870 #if 1
5871         if (door_part_skip[nr])
5872           continue;
5873 #endif
5874
5875         if (!(door_state & door_token))
5876           continue;
5877
5878         if (!g->bitmap)
5879           continue;
5880
5881 #if 0
5882         if (current_move_delay % step_delay)
5883           continue;
5884 #endif
5885
5886         // draw door panel
5887
5888         if (!door_panel_drawn[door_index])
5889         {
5890 #if 1
5891           ClearRectangle(drawto, door_rect->x, door_rect->y,
5892                          door_rect->width, door_rect->height);
5893 #else
5894           BlitBitmap(bitmap_db_door, drawto, panel_pos->x, panel_pos->y,
5895                      door_rect->width, door_rect->height,
5896                      door_rect->x, door_rect->y);
5897 #endif
5898
5899           door_panel_drawn[door_index] = TRUE;
5900         }
5901
5902         // draw opening or closing door parts
5903
5904         if (pos->step_xoffset < 0)      // door part on right side
5905         {
5906           src_xx = 0;
5907           dst_xx = pos->x + ABS(kk * pos->step_xoffset);
5908           width = g->width;
5909
5910           if (dst_xx + width > door_rect->width)
5911             width = door_rect->width - dst_xx;
5912         }
5913         else                            // door part on left side
5914         {
5915           src_xx = 0;
5916           dst_xx = pos->x - kk * pos->step_xoffset;
5917
5918           if (dst_xx < 0)
5919           {
5920             src_xx = ABS(dst_xx);
5921             dst_xx = 0;
5922           }
5923
5924           width = g->width - src_xx;
5925
5926           // printf("::: k == %d [%d] \n", k, start_step);
5927         }
5928
5929         if (pos->step_yoffset < 0)      // door part on bottom side
5930         {
5931           src_yy = 0;
5932           dst_yy = pos->y + ABS(kk * pos->step_yoffset);
5933           height = g->height;
5934
5935           if (dst_yy + height > door_rect->height)
5936             height = door_rect->height - dst_yy;
5937         }
5938         else                            // door part on top side
5939         {
5940           src_yy = 0;
5941           dst_yy = pos->y - kk * pos->step_yoffset;
5942
5943           if (dst_yy < 0)
5944           {
5945             src_yy = ABS(dst_yy);
5946             dst_yy = 0;
5947           }
5948
5949           height = g->height - src_yy;
5950         }
5951
5952         if (is_panel)
5953         {
5954 #if 1
5955           src_x = src_xx;
5956           src_y = src_yy;
5957 #else
5958           src_x = panel_pos->x + src_xx;
5959           src_y = panel_pos->y + src_yy;
5960 #endif
5961         }
5962         else
5963         {
5964           src_x = g->src_x + src_xx;
5965           src_y = g->src_y + src_yy;
5966         }
5967
5968         dst_x = door_rect->x + dst_xx;
5969         dst_y = door_rect->y + dst_yy;
5970
5971 #if 0
5972         if (DOOR_PART_IS_PANEL(nr))
5973         {
5974           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5975                  width, height, g->width, g->height, src_x, src_y);
5976         }
5977 #endif
5978
5979         if (width  >= 0 && width  <= g->width &&
5980             height >= 0 && height <= g->height)
5981         {
5982           if (is_panel || !pos->draw_masked)
5983             BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
5984                        dst_x, dst_y);
5985           else
5986             BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
5987                              dst_x, dst_y);
5988         }
5989
5990 #if 0
5991         if (DOOR_PART_IS_PANEL(nr))
5992         {
5993           bitmap = bitmap_db_door;
5994           src_x = panel_pos->x + src_xx;
5995           src_y = panel_pos->y + src_yy;
5996
5997           printf("::: width == %d, height == %d [%d, %d] [%d, %d]\n",
5998                  width, height, g->width, g->height, src_x, src_y);
5999
6000           if (width  >= 0 && width  <= g->width &&
6001               height >= 0 && height <= g->height)
6002             BlitBitmap(bitmap, drawto, src_x, src_y,
6003                              width, height,
6004                              dst_x, dst_y);
6005         }
6006 #endif
6007
6008         redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
6009
6010 #if 1
6011         if ((part_opening && (width < 0         || height < 0)) ||
6012             (part_closing && (width >= g->width && height >= g->height)))
6013           door_part_done[nr] = TRUE;
6014 #else
6015         if ((door_opening && (width < 0         || height < 0)) ||
6016             (door_closing && (width >= g->width && height >= g->height)))
6017           door_part_done[nr] = TRUE;
6018 #endif
6019
6020 #if 1
6021         // continue door part animations, but not panel after door has closed
6022         if (!door_part_done[nr] &&
6023             !(is_panel && door_closing && panel_has_doors[door_index]))
6024           door_part_done_all = FALSE;
6025 #else
6026         // continue door part animations, but not panel after door has closed
6027         if (!door_part_done[nr] && !(is_panel && door_closing))
6028           door_part_done_all = FALSE;
6029 #endif
6030
6031 #if 0
6032         if (!door_part_done[nr])
6033           printf("::: k == %d, nr == %d\n", k, nr);
6034 #endif
6035       }
6036
6037       if (!(door_state & DOOR_NO_DELAY))
6038       {
6039         BackToFront();
6040
6041         if (game_status == GAME_MODE_MAIN)
6042           DoAnimation();
6043
6044         WaitUntilDelayReached(&door_delay, door_delay_value);
6045
6046         current_move_delay += max_step_delay;
6047       }
6048
6049 #if 0
6050       door_part_done_all = TRUE;
6051
6052       for (i = 0; i < MAX_DOOR_PARTS; i++)
6053         if (!door_part_done[i] &&
6054             !(DOOR_PART_IS_PANEL(i) && door_closing))
6055           door_part_done_all = FALSE;
6056 #endif
6057 #if 1
6058       if (door_part_done_all)
6059         break;
6060 #endif
6061     }
6062   }
6063
6064   if (door_state & DOOR_ACTION_1)
6065     door1 = door_state & DOOR_ACTION_1;
6066   if (door_state & DOOR_ACTION_2)
6067     door2 = door_state & DOOR_ACTION_2;
6068
6069 #if 0
6070   printf("::: DOORS DONE %08x\n", door_state);
6071   Delay(3000);
6072   printf("::: GO!\n");
6073 #endif
6074
6075   return (door1 | door2);
6076 }
6077
6078 #else
6079
6080 // ========== OLD ==============================================================
6081
6082 unsigned int MoveDoor(unsigned int door_state)
6083 {
6084   static int door1 = DOOR_OPEN_1;
6085   static int door2 = DOOR_CLOSE_2;
6086   unsigned int door_delay = 0;
6087   unsigned int door_delay_value;
6088   int stepsize = 1;
6089
6090 #if 1
6091   if (door_1.width < 0 || door_1.width > DXSIZE)
6092     door_1.width = DXSIZE;
6093   if (door_1.height < 0 || door_1.height > DYSIZE)
6094     door_1.height = DYSIZE;
6095   if (door_2.width < 0 || door_2.width > VXSIZE)
6096     door_2.width = VXSIZE;
6097   if (door_2.height < 0 || door_2.height > VYSIZE)
6098     door_2.height = VYSIZE;
6099 #endif
6100
6101   if (door_state == DOOR_GET_STATE)
6102     return (door1 | door2);
6103
6104   if (door_state & DOOR_SET_STATE)
6105   {
6106     if (door_state & DOOR_ACTION_1)
6107       door1 = door_state & DOOR_ACTION_1;
6108     if (door_state & DOOR_ACTION_2)
6109       door2 = door_state & DOOR_ACTION_2;
6110
6111     return (door1 | door2);
6112   }
6113
6114   if (!(door_state & DOOR_FORCE_REDRAW))
6115   {
6116     if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
6117       door_state &= ~DOOR_OPEN_1;
6118     else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
6119       door_state &= ~DOOR_CLOSE_1;
6120     if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
6121       door_state &= ~DOOR_OPEN_2;
6122     else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
6123       door_state &= ~DOOR_CLOSE_2;
6124   }
6125
6126   door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
6127                       door_2.step_delay);
6128
6129   // door_delay_value *= 4;     // !!! TEST ONLY !!!
6130
6131   if (setup.quick_doors)
6132   {
6133     stepsize = 20;              /* must be chosen to always draw last frame */
6134     door_delay_value = 0;
6135   }
6136
6137   if (global.autoplay_leveldir)
6138   {
6139     door_state |= DOOR_NO_DELAY;
6140     door_state &= ~DOOR_CLOSE_ALL;
6141   }
6142
6143 #if 1
6144   if (game_status == GAME_MODE_EDITOR)
6145     door_state |= DOOR_NO_DELAY;
6146 #endif
6147
6148   if (door_state & DOOR_ACTION)
6149   {
6150 #if 1
6151     struct GraphicInfo *g1_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6152     struct GraphicInfo *g1_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6153     struct GraphicInfo *g2_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6154     struct GraphicInfo *g2_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6155     int door_1_left_width   = g1_left->width;
6156     int door_1_left_height  = g1_left->height;
6157     int door_1_right_width  = g1_right->width;
6158     int door_1_right_height = g1_right->height;
6159     int door_2_left_width   = g2_left->width;
6160     int door_2_left_height  = g2_left->height;
6161     int door_2_right_width  = g2_right->width;
6162     int door_2_right_height = g2_right->height;
6163     int door_1_width  = MAX(door_1_left_width,  door_1_right_width);
6164     int door_1_height = MAX(door_1_left_height, door_1_right_height);
6165     int door_2_width  = MAX(door_2_left_width,  door_2_right_width);
6166     int door_2_height = MAX(door_2_left_height, door_2_right_height);
6167 #endif
6168     boolean handle_door_1 = (door_state & DOOR_ACTION_1);
6169     boolean handle_door_2 = (door_state & DOOR_ACTION_2);
6170     boolean door_1_done = (!handle_door_1);
6171     boolean door_2_done = (!handle_door_2);
6172     boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
6173     boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
6174 #if 1
6175 #if 1
6176     int door_size_1 = (door_1_vertical ? door_1_height : door_1_width);
6177     int door_size_2 = (door_2_vertical ? door_2_height : door_2_width);
6178 #else
6179     int door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6180     int door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6181 #endif
6182 #else
6183     int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
6184     int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
6185 #endif
6186     int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
6187     int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
6188     // int door_size     = (handle_door_1 ? door_size_1     : door_size_2);
6189     int door_size     = (handle_door_2 ? door_size_2     : door_size_1);
6190     int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
6191     int door_skip = max_door_size - door_size;
6192     int end = door_size;
6193     int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
6194     int k;
6195
6196     if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
6197     {
6198       /* opening door sound has priority over simultaneously closing door */
6199       if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
6200         PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
6201       else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
6202         PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
6203     }
6204
6205     for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
6206     {
6207       int x = k;
6208 #if 0
6209       Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6210       GC gc = bitmap->stored_clip_gc;
6211 #endif
6212
6213       if (door_state & DOOR_ACTION_1 &&
6214           x * door_1.step_offset <= door_size_1)
6215       {
6216         int a = MIN(x * door_1.step_offset, end);
6217         int p = (door_state & DOOR_OPEN_1 ? end - a : a);
6218 #if 1
6219         int i = p;
6220 #else
6221         int i = p + door_skip;
6222 #endif
6223
6224 #if 1
6225         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_1_WING_LEFT];
6226         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_1_WING_RIGHT];
6227         Bitmap *bm_left  = g_left->bitmap;
6228         Bitmap *bm_right = g_right->bitmap;
6229         GC gc_left  = bm_left->stored_clip_gc;
6230         GC gc_right = bm_right->stored_clip_gc;
6231 #endif
6232
6233         int classic_dxsize = 100;
6234         int classic_dysize = 280;
6235         boolean classic_door_1_size = (DXSIZE == classic_dxsize &&
6236                                        DYSIZE == classic_dysize);
6237
6238         if (door_1.anim_mode & ANIM_STATIC_PANEL)
6239         {
6240           BlitBitmap(bitmap_db_door, drawto,
6241                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
6242                      DXSIZE, DYSIZE, DX, DY);
6243         }
6244         else if (x <= a)
6245         {
6246           BlitBitmap(bitmap_db_door, drawto,
6247                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
6248                      DXSIZE, DYSIZE - p / 2, DX, DY);
6249
6250 #if 1
6251           // printf("::: p == %d\n", p);
6252           ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
6253 #endif
6254         }
6255
6256         if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
6257         {
6258 #if 1
6259           int src1_x = g_right->src_x;
6260           int src1_y = g_right->src_y;
6261           int src2_x = g_left->src_x + g_left->width - i;
6262           int src2_y = g_left->src_y;
6263           int dst1_x = DX + DXSIZE - i;
6264           int dst1_y = DY;
6265           int dst2_x = DX;
6266           int dst2_y = DY;
6267           int width = i;
6268           int height = DYSIZE;
6269
6270           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6271           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6272                            dst1_x, dst1_y);
6273
6274           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6275           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6276                            dst2_x, dst2_y);
6277 #else
6278           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6279           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6280           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6281           int dst2_x = DX,              dst2_y = DY;
6282           int width = i, height = DYSIZE;
6283
6284           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6285           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6286                            dst1_x, dst1_y);
6287
6288           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6289           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6290                            dst2_x, dst2_y);
6291 #endif
6292         }
6293         else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
6294         {
6295 #if 1
6296           int src1_x = g_right->src_x;
6297           int src1_y = g_right->src_y;
6298           int src2_x = g_left->src_x;
6299           int src2_y = g_left->src_y + g_left->height - i;
6300           int dst1_x = DX;
6301           int dst1_y = DY + DYSIZE - i;
6302           int dst2_x = DX;
6303           int dst2_y = DY;
6304           int width = DXSIZE;
6305           int height = i;
6306
6307           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6308           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6309                            dst1_x, dst1_y);
6310
6311           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6312           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6313                            dst2_x, dst2_y);
6314 #else
6315           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6316           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
6317           int dst1_x = DX,              dst1_y = DY + DYSIZE - i;
6318           int dst2_x = DX,              dst2_y = DY;
6319           int width = DXSIZE, height = i;
6320
6321           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6322           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6323                            dst1_x, dst1_y);
6324
6325           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6326           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6327                            dst2_x, dst2_y);
6328 #endif
6329         }
6330         else if (classic_door_1_size && x <= DXSIZE)    /* ANIM_DEFAULT */
6331         {
6332           int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
6333
6334 #if 1
6335           int src1_x = g_right->src_x;
6336           int src1_y = g_right->src_y;
6337           int src2_x = g_left->src_x + g_left->width - i;
6338           int src2_y = g_left->src_y;
6339           int dst1_x = DX + DXSIZE - i;
6340           int dst1_y = DY;
6341           int dst2_x = DX;
6342           int dst2_y = DY;
6343           int width = i;
6344           int height1 = 63, height2 = DYSIZE / 2 - height1;
6345           int ypos1 = 0, ypos2 = height2;
6346           int ypos3 = DYSIZE / 2, ypos4 = DYSIZE - height2;
6347
6348           SetClipOrigin(bm_right, gc_right,
6349                         dst1_x - src1_x, dst1_y - src1_y + j);
6350           BlitBitmapMasked(bm_right, drawto,
6351                            src1_x, src1_y + ypos1, width, height2,
6352                            dst1_x, dst1_y + ypos1 + j);
6353           BlitBitmapMasked(bm_right, drawto,
6354                            src1_x, src1_y + ypos3, width, height1,
6355                            dst1_x, dst1_y + ypos3 + j);
6356           SetClipOrigin(bm_left, gc_left,
6357                         dst2_x - src2_x, dst2_y - src2_y - j);
6358           BlitBitmapMasked(bm_left, drawto,
6359                            src2_x, src2_y + ypos1 + j, width, height2 - j,
6360                            dst2_x, dst2_y + ypos1);
6361           BlitBitmapMasked(bm_left, drawto,
6362                            src2_x, src2_y + ypos3, width, height1,
6363                            dst2_x, dst2_y + ypos3 - j);
6364
6365           SetClipOrigin(bm_left, gc_left,
6366                         dst2_x - src2_x, dst2_y - src2_y - j);
6367           BlitBitmapMasked(bm_left, drawto,
6368                            src2_x, src2_y + ypos2, width, height1,
6369                            dst2_x, dst2_y + ypos2 - j);
6370           BlitBitmapMasked(bm_left, drawto,
6371                            src2_x, src2_y + ypos4, width, height2,
6372                            dst2_x, dst2_y + ypos4 - j);
6373           SetClipOrigin(bm_right, gc_right,
6374                         dst1_x - src1_x, dst1_y - src1_y + j);
6375           BlitBitmapMasked(bm_right, drawto,
6376                            src1_x, src1_y + ypos2, width, height1,
6377                            dst1_x, dst1_y + ypos2 + j);
6378           BlitBitmapMasked(bm_right, drawto,
6379                            src1_x, src1_y + ypos4, width, height2 - j,
6380                            dst1_x, dst1_y + ypos4 + j);
6381
6382 #else
6383           int src1_x = DXSIZE,          src1_y = DOOR_GFX_PAGEY1;
6384           int src2_x = DXSIZE - i,      src2_y = DOOR_GFX_PAGEY1;
6385           int dst1_x = DX + DXSIZE - i, dst1_y = DY;
6386           int dst2_x = DX,              dst2_y = DY;
6387           int width = i, height = DYSIZE;
6388           int ypos1 = 63, ypos2 = 77, ypos3 = 140, ypos4 = 203;
6389
6390           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6391           BlitBitmapMasked(bitmap, drawto,
6392                            src1_x, src1_y, width, ypos2,
6393                            dst1_x, dst1_y + j);
6394           BlitBitmapMasked(bitmap, drawto,
6395                            src1_x, src1_y + ypos3, width, ypos1,
6396                            dst1_x, dst1_y + ypos3 + j);
6397           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6398           BlitBitmapMasked(bitmap, drawto,
6399                            src2_x, src2_y + j, width, ypos2 - j,
6400                            dst2_x, dst2_y);
6401           BlitBitmapMasked(bitmap, drawto,
6402                            src2_x, src2_y + ypos3, width, ypos1,
6403                            dst2_x, dst2_y + ypos3 - j);
6404
6405           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y - j);
6406           BlitBitmapMasked(bitmap, drawto,
6407                            src2_x, src2_y + ypos2, width, ypos1,
6408                            dst2_x, dst2_y + ypos2 - j);
6409           BlitBitmapMasked(bitmap, drawto,
6410                            src2_x, src2_y + ypos4, width, ypos2,
6411                            dst2_x, dst2_y + ypos4 - j);
6412           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6413           BlitBitmapMasked(bitmap, drawto,
6414                            src1_x, src1_y + ypos2, width, ypos1,
6415                            dst1_x, dst1_y + ypos2 + j);
6416           BlitBitmapMasked(bitmap, drawto,
6417                            src1_x, src1_y + ypos4, width, ypos2 - j,
6418                            dst1_x, dst1_y + ypos4 + j);
6419
6420           /*
6421           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6422           BlitBitmapMasked(bitmap, drawto,
6423                            DXSIZE, DOOR_GFX_PAGEY1, i, 77,
6424                            DX + DXSIZE - i, DY + j);
6425           BlitBitmapMasked(bitmap, drawto,
6426                            DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
6427                            DX + DXSIZE - i, DY + 140 + j);
6428           SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
6429                         DY - (DOOR_GFX_PAGEY1 + j));
6430           BlitBitmapMasked(bitmap, drawto,
6431                            DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
6432                            DX, DY);
6433           BlitBitmapMasked(bitmap, drawto,
6434                            DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
6435                            DX, DY + 140 - j);
6436
6437           BlitBitmapMasked(bitmap, drawto,
6438                            DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
6439                            DX, DY + 77 - j);
6440           BlitBitmapMasked(bitmap, drawto,
6441                            DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
6442                            DX, DY + 203 - j);
6443           SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
6444           BlitBitmapMasked(bitmap, drawto,
6445                            DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
6446                            DX + DXSIZE - i, DY + 77 + j);
6447           BlitBitmapMasked(bitmap, drawto,
6448                            DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
6449                            DX + DXSIZE - i, DY + 203 + j);
6450           */
6451 #endif
6452         }
6453
6454         redraw_mask |= REDRAW_DOOR_1;
6455         door_1_done = (a == end);
6456       }
6457
6458       if (door_state & DOOR_ACTION_2 &&
6459           x * door_2.step_offset <= door_size_2)
6460       {
6461         int a = MIN(x * door_2.step_offset, door_size);
6462         int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
6463         int i = p + door_skip;
6464
6465 #if 1
6466         struct GraphicInfo *g_left  = &graphic_info[IMG_DOOR_2_WING_LEFT];
6467         struct GraphicInfo *g_right = &graphic_info[IMG_DOOR_2_WING_RIGHT];
6468         Bitmap *bm_left  = g_left->bitmap;
6469         Bitmap *bm_right = g_right->bitmap;
6470         GC gc_left  = bm_left->stored_clip_gc;
6471         GC gc_right = bm_right->stored_clip_gc;
6472 #endif
6473
6474         int classic_vxsize = 100;
6475         int classic_vysize = 100;
6476         boolean classic_door_2_size = (VXSIZE == classic_vxsize &&
6477                                        VYSIZE == classic_vysize);
6478
6479         if (door_2.anim_mode & ANIM_STATIC_PANEL)
6480         {
6481           BlitBitmap(bitmap_db_door, drawto,
6482                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
6483                      VXSIZE, VYSIZE, VX, VY);
6484         }
6485         else if (x <= VYSIZE)
6486         {
6487           BlitBitmap(bitmap_db_door, drawto,
6488                      DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
6489                      VXSIZE, VYSIZE - p / 2, VX, VY);
6490
6491           ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
6492         }
6493
6494         if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
6495         {
6496 #if 1
6497           int src1_x = g_right->src_x;
6498           int src1_y = g_right->src_y;
6499           int src2_x = g_left->src_x + g_left->width - i;
6500           int src2_y = g_left->src_y;
6501           int dst1_x = VX + VXSIZE - i;
6502           int dst1_y = VY;
6503           int dst2_x = VX;
6504           int dst2_y = VY;
6505           int width = i;
6506           int height = VYSIZE;
6507
6508           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6509           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6510                            dst1_x, dst1_y);
6511
6512           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6513           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6514                            dst2_x, dst2_y);
6515 #else
6516           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6517           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6518           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6519           int dst2_x = VX,              dst2_y = VY;
6520           int width = i, height = VYSIZE;
6521
6522           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6523           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6524                            dst1_x, dst1_y);
6525
6526           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6527           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6528                            dst2_x, dst2_y);
6529 #endif
6530         }
6531         else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
6532         {
6533 #if 1
6534           int src1_x = g_right->src_x;
6535           int src1_y = g_right->src_y;
6536           int src2_x = g_left->src_x;
6537           int src2_y = g_left->src_y + g_left->height - i;
6538           int dst1_x = VX;
6539           int dst1_y = VY + VYSIZE - i;
6540           int dst2_x = VX;
6541           int dst2_y = VY;
6542           int width = VXSIZE;
6543           int height = i;
6544
6545           SetClipOrigin(bm_right, gc_right, dst1_x - src1_x, dst1_y - src1_y);
6546           BlitBitmapMasked(bm_right, drawto, src1_x, src1_y, width, height,
6547                            dst1_x, dst1_y);
6548
6549           SetClipOrigin(bm_left, gc_left, dst2_x - src2_x, dst2_y - src2_y);
6550           BlitBitmapMasked(bm_left, drawto, src2_x, src2_y, width, height,
6551                            dst2_x, dst2_y);
6552 #else
6553           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6554           int src2_x = 0,               src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
6555           int dst1_x = VX,              dst1_y = VY + VYSIZE - i;
6556           int dst2_x = VX,              dst2_y = VY;
6557           int width = VXSIZE, height = i;
6558
6559           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
6560           BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
6561                            dst1_x, dst1_y);
6562
6563           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
6564           BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
6565                            dst2_x, dst2_y);
6566 #endif
6567         }
6568         else if (classic_door_2_size && x <= VXSIZE)    /* ANIM_DEFAULT */
6569         {
6570           int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
6571
6572 #if 1
6573           int src1_x = g_right->src_x;
6574           int src1_y = g_right->src_y;
6575           int src2_x = g_left->src_x + g_left->width - i;
6576           int src2_y = g_left->src_y;
6577           int dst1_x = VX + VXSIZE - i;
6578           int dst1_y = VY;
6579           int dst2_x = VX;
6580           int dst2_y = VY;
6581           int width = i;
6582           int height = VYSIZE / 2;
6583           int ypos1 = 0, ypos2 = VYSIZE / 2;
6584
6585           SetClipOrigin(bm_right, gc_right,
6586                         dst1_x - src1_x, dst1_y - src1_y + j);
6587           BlitBitmapMasked(bm_right, drawto,
6588                            src1_x, src1_y + ypos1, width, height,
6589                            dst1_x, dst1_y + ypos1 + j);
6590           SetClipOrigin(bm_left, gc_left,
6591                         dst2_x - src2_x, dst2_y - src2_y - j);
6592           BlitBitmapMasked(bm_left, drawto,
6593                            src2_x, src2_y + ypos1 + j, width, height - j,
6594                            dst2_x, dst2_y + ypos1);
6595
6596           SetClipOrigin(bm_left, gc_left,
6597                         dst2_x - src2_x, dst2_y - src2_y - j);
6598           BlitBitmapMasked(bm_left, drawto,
6599                            src2_x, src2_y + ypos2, width, height,
6600                            dst2_x, dst2_y + ypos2 - j);
6601           SetClipOrigin(bm_right, gc_right,
6602                         dst1_x - src1_x, dst1_y - src1_y + j);
6603           BlitBitmapMasked(bm_right, drawto,
6604                            src1_x, src1_y + ypos2, width, height - j,
6605                            dst1_x, dst1_y + ypos2 + j);
6606 #else
6607           int src1_x = VXSIZE,          src1_y = DOOR_GFX_PAGEY2;
6608           int src2_x = VXSIZE - i,      src2_y = DOOR_GFX_PAGEY2;
6609           int dst1_x = VX + VXSIZE - i, dst1_y = VY;
6610           int dst2_x = VX,              dst2_y = VY;
6611           int width = i, height = VYSIZE;
6612           int ypos = VYSIZE / 2;
6613
6614           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6615           BlitBitmapMasked(bitmap, drawto,
6616                            src1_x, src1_y, width, ypos,
6617                            dst1_x, dst1_y + j);
6618           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6619           BlitBitmapMasked(bitmap, drawto,
6620                            src2_x, src2_y + j, width, ypos - j,
6621                            dst2_x, dst2_y);
6622
6623           SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src1_y - j);
6624           BlitBitmapMasked(bitmap, drawto,
6625                            src2_x, src2_y + ypos, width, ypos,
6626                            dst2_x, dst2_y + ypos - j);
6627           SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y + j);
6628           BlitBitmapMasked(bitmap, drawto,
6629                            src1_x, src1_y + ypos, width, ypos - j,
6630                            dst1_x, dst1_y + ypos + j);
6631
6632           /*
6633           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6634           BlitBitmapMasked(bitmap, drawto,
6635                            VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
6636                            VX + VXSIZE - i, VY + j);
6637           SetClipOrigin(bitmap, gc,
6638                         VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
6639           BlitBitmapMasked(bitmap, drawto,
6640                            VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
6641                            VX, VY);
6642
6643           BlitBitmapMasked(bitmap, drawto,
6644                            VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6645                            i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
6646           SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
6647           BlitBitmapMasked(bitmap, drawto,
6648                            VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
6649                            i, VYSIZE / 2 - j,
6650                            VX + VXSIZE - i, VY + VYSIZE / 2 + j);
6651           */
6652 #endif
6653         }
6654
6655         redraw_mask |= REDRAW_DOOR_2;
6656         door_2_done = (a == VXSIZE);
6657       }
6658
6659       if (!(door_state & DOOR_NO_DELAY))
6660       {
6661         BackToFront();
6662
6663         if (game_status == GAME_MODE_MAIN)
6664           DoAnimation();
6665
6666         WaitUntilDelayReached(&door_delay, door_delay_value);
6667       }
6668     }
6669   }
6670
6671   if (door_state & DOOR_ACTION_1)
6672     door1 = door_state & DOOR_ACTION_1;
6673   if (door_state & DOOR_ACTION_2)
6674     door2 = door_state & DOOR_ACTION_2;
6675
6676   return (door1 | door2);
6677 }
6678
6679 #endif
6680
6681 void DrawSpecialEditorDoor()
6682 {
6683 #if 1
6684   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6685   int top_border_width = gfx1->width;
6686   int top_border_height = gfx1->height;
6687   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6688   int ex = EX - outer_border;
6689   int ey = EY - outer_border;
6690   int vy = VY - outer_border;
6691   int exsize = EXSIZE + 2 * outer_border;
6692
6693   CloseDoor(DOOR_CLOSE_2);
6694
6695   /* draw bigger level editor toolbox window */
6696   BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
6697              top_border_width, top_border_height, ex, ey - top_border_height);
6698   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
6699              exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
6700 #else
6701   /* draw bigger level editor toolbox window */
6702   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
6703              DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
6704              EX - 4, EY - 12);
6705   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6706              EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
6707              EX - 6, EY - 4);
6708 #endif
6709
6710   redraw_mask |= REDRAW_ALL;
6711 }
6712
6713 void UndrawSpecialEditorDoor()
6714 {
6715 #if 1
6716   struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
6717   int top_border_width = gfx1->width;
6718   int top_border_height = gfx1->height;
6719   int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
6720   int ex = EX - outer_border;
6721   int ey = EY - outer_border;
6722   int ey_top = ey - top_border_height;
6723   int exsize = EXSIZE + 2 * outer_border;
6724   int eysize = EYSIZE + 2 * outer_border;
6725
6726   /* draw normal tape recorder window */
6727   if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
6728   {
6729     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6730                ex, ey_top, top_border_width, top_border_height,
6731                ex, ey_top);
6732     BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6733                ex, ey, exsize, eysize, ex, ey);
6734   }
6735   else
6736   {
6737     // if screen background is set to "[NONE]", clear editor toolbox window
6738     ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
6739     ClearRectangle(drawto, ex, ey, exsize, eysize);
6740   }
6741 #else
6742   /* draw normal tape recorder window */
6743   BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
6744              EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
6745              EX - 6, EY - 12);
6746 #endif
6747
6748   redraw_mask |= REDRAW_ALL;
6749 }
6750
6751
6752 /* ---------- new tool button stuff ---------------------------------------- */
6753
6754 #if 1
6755
6756 static struct
6757 {
6758   int graphic;
6759   struct TextPosInfo *pos;
6760   int gadget_id;
6761   char *infotext;
6762 } toolbutton_info[NUM_TOOL_BUTTONS] =
6763 {
6764   {
6765     IMG_REQUEST_BUTTON_GFX_YES,         &request.button.yes,
6766     TOOL_CTRL_ID_YES,                   "yes"
6767   },
6768   {
6769     IMG_REQUEST_BUTTON_GFX_NO,          &request.button.no,
6770     TOOL_CTRL_ID_NO,                    "no"
6771   },
6772   {
6773     IMG_REQUEST_BUTTON_GFX_CONFIRM,     &request.button.confirm,
6774     TOOL_CTRL_ID_CONFIRM,               "confirm"
6775   },
6776   {
6777     IMG_REQUEST_BUTTON_GFX_PLAYER_1,    &request.button.player_1,
6778     TOOL_CTRL_ID_PLAYER_1,              "player 1"
6779   },
6780   {
6781     IMG_REQUEST_BUTTON_GFX_PLAYER_2,    &request.button.player_2,
6782     TOOL_CTRL_ID_PLAYER_2,              "player 2"
6783   },
6784   {
6785     IMG_REQUEST_BUTTON_GFX_PLAYER_3,    &request.button.player_3,
6786     TOOL_CTRL_ID_PLAYER_3,              "player 3"
6787   },
6788   {
6789     IMG_REQUEST_BUTTON_GFX_PLAYER_4,    &request.button.player_4,
6790     TOOL_CTRL_ID_PLAYER_4,              "player 4"
6791   }
6792 };
6793
6794 void CreateToolButtons()
6795 {
6796   int i;
6797
6798   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6799   {
6800     struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
6801     struct TextPosInfo *pos = toolbutton_info[i].pos;
6802     struct GadgetInfo *gi;
6803     Bitmap *deco_bitmap = None;
6804     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6805     unsigned int event_mask = GD_EVENT_RELEASED;
6806     int dx = DX;
6807     int dy = DY;
6808     int gd_x = gfx->src_x;
6809     int gd_y = gfx->src_y;
6810     int gd_xp = gfx->src_x + gfx->pressed_xoffset;
6811     int gd_yp = gfx->src_y + gfx->pressed_yoffset;
6812     int id = i;
6813
6814     if (global.use_envelope_request)
6815       setRequestPosition(&dx, &dy, TRUE);
6816
6817     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6818     {
6819       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6820
6821       getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
6822                             pos->size, &deco_bitmap, &deco_x, &deco_y);
6823       deco_xpos = (gfx->width  - pos->size) / 2;
6824       deco_ypos = (gfx->height - pos->size) / 2;
6825     }
6826
6827     gi = CreateGadget(GDI_CUSTOM_ID, id,
6828                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
6829                       GDI_X, dx + GDI_ACTIVE_POS(pos->x),
6830                       GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
6831                       GDI_WIDTH, gfx->width,
6832                       GDI_HEIGHT, gfx->height,
6833                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6834                       GDI_STATE, GD_BUTTON_UNPRESSED,
6835                       GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
6836                       GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
6837                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6838                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6839                       GDI_DECORATION_SIZE, pos->size, pos->size,
6840                       GDI_DECORATION_SHIFTING, 1, 1,
6841                       GDI_DIRECT_DRAW, FALSE,
6842                       GDI_EVENT_MASK, event_mask,
6843                       GDI_CALLBACK_ACTION, HandleToolButtons,
6844                       GDI_END);
6845
6846     if (gi == NULL)
6847       Error(ERR_EXIT, "cannot create gadget");
6848
6849     tool_gadget[id] = gi;
6850   }
6851 }
6852
6853 #else
6854
6855 /* graphic position values for tool buttons */
6856 #define TOOL_BUTTON_YES_XPOS            2
6857 #define TOOL_BUTTON_YES_YPOS            250
6858 #define TOOL_BUTTON_YES_GFX_YPOS        0
6859 #define TOOL_BUTTON_YES_XSIZE           46
6860 #define TOOL_BUTTON_YES_YSIZE           28
6861 #define TOOL_BUTTON_NO_XPOS             52
6862 #define TOOL_BUTTON_NO_YPOS             TOOL_BUTTON_YES_YPOS
6863 #define TOOL_BUTTON_NO_GFX_YPOS         TOOL_BUTTON_YES_GFX_YPOS
6864 #define TOOL_BUTTON_NO_XSIZE            TOOL_BUTTON_YES_XSIZE
6865 #define TOOL_BUTTON_NO_YSIZE            TOOL_BUTTON_YES_YSIZE
6866 #define TOOL_BUTTON_CONFIRM_XPOS        TOOL_BUTTON_YES_XPOS
6867 #define TOOL_BUTTON_CONFIRM_YPOS        TOOL_BUTTON_YES_YPOS
6868 #define TOOL_BUTTON_CONFIRM_GFX_YPOS    30
6869 #define TOOL_BUTTON_CONFIRM_XSIZE       96
6870 #define TOOL_BUTTON_CONFIRM_YSIZE       TOOL_BUTTON_YES_YSIZE
6871 #define TOOL_BUTTON_PLAYER_XSIZE        30
6872 #define TOOL_BUTTON_PLAYER_YSIZE        30
6873 #define TOOL_BUTTON_PLAYER_GFX_XPOS     5
6874 #define TOOL_BUTTON_PLAYER_GFX_YPOS     185
6875 #define TOOL_BUTTON_PLAYER_XPOS         (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
6876 #define TOOL_BUTTON_PLAYER_YPOS         (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
6877 #define TOOL_BUTTON_PLAYER1_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6878                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6879 #define TOOL_BUTTON_PLAYER2_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6880                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6881 #define TOOL_BUTTON_PLAYER3_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6882                                          + 0 * TOOL_BUTTON_PLAYER_XSIZE)
6883 #define TOOL_BUTTON_PLAYER4_XPOS        (TOOL_BUTTON_PLAYER_XPOS \
6884                                          + 1 * TOOL_BUTTON_PLAYER_XSIZE)
6885 #define TOOL_BUTTON_PLAYER1_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6886                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6887 #define TOOL_BUTTON_PLAYER2_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6888                                          + 0 * TOOL_BUTTON_PLAYER_YSIZE)
6889 #define TOOL_BUTTON_PLAYER3_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6890                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6891 #define TOOL_BUTTON_PLAYER4_YPOS        (TOOL_BUTTON_PLAYER_YPOS \
6892                                          + 1 * TOOL_BUTTON_PLAYER_YSIZE)
6893
6894 static struct
6895 {
6896   int xpos, ypos;
6897   int x, y;
6898   int width, height;
6899   int gadget_id;
6900   char *infotext;
6901 } toolbutton_info[NUM_TOOL_BUTTONS] =
6902 {
6903   {
6904     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_GFX_YPOS,
6905     TOOL_BUTTON_YES_XPOS,       TOOL_BUTTON_YES_YPOS,
6906     TOOL_BUTTON_YES_XSIZE,      TOOL_BUTTON_YES_YSIZE,
6907     TOOL_CTRL_ID_YES,
6908     "yes"
6909   },
6910   {
6911     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_GFX_YPOS,
6912     TOOL_BUTTON_NO_XPOS,        TOOL_BUTTON_NO_YPOS,
6913     TOOL_BUTTON_NO_XSIZE,       TOOL_BUTTON_NO_YSIZE,
6914     TOOL_CTRL_ID_NO,
6915     "no"
6916   },
6917   {
6918     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_GFX_YPOS,
6919     TOOL_BUTTON_CONFIRM_XPOS,   TOOL_BUTTON_CONFIRM_YPOS,
6920     TOOL_BUTTON_CONFIRM_XSIZE,  TOOL_BUTTON_CONFIRM_YSIZE,
6921     TOOL_CTRL_ID_CONFIRM,
6922     "confirm"
6923   },
6924   {
6925     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6926     TOOL_BUTTON_PLAYER1_XPOS,   TOOL_BUTTON_PLAYER1_YPOS,
6927     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6928     TOOL_CTRL_ID_PLAYER_1,
6929     "player 1"
6930   },
6931   {
6932     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6933     TOOL_BUTTON_PLAYER2_XPOS,   TOOL_BUTTON_PLAYER2_YPOS,
6934     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6935     TOOL_CTRL_ID_PLAYER_2,
6936     "player 2"
6937   },
6938   {
6939     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6940     TOOL_BUTTON_PLAYER3_XPOS,   TOOL_BUTTON_PLAYER3_YPOS,
6941     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6942     TOOL_CTRL_ID_PLAYER_3,
6943     "player 3"
6944   },
6945   {
6946     TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
6947     TOOL_BUTTON_PLAYER4_XPOS,   TOOL_BUTTON_PLAYER4_YPOS,
6948     TOOL_BUTTON_PLAYER_XSIZE,   TOOL_BUTTON_PLAYER_YSIZE,
6949     TOOL_CTRL_ID_PLAYER_4,
6950     "player 4"
6951   }
6952 };
6953
6954 void CreateToolButtons()
6955 {
6956   int i;
6957
6958   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
6959   {
6960     Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
6961     Bitmap *deco_bitmap = None;
6962     int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
6963     struct GadgetInfo *gi;
6964     unsigned int event_mask;
6965     int gd_xoffset, gd_yoffset;
6966     int gd_x1, gd_x2, gd_y;
6967     int id = i;
6968
6969     event_mask = GD_EVENT_RELEASED;
6970
6971     gd_xoffset = toolbutton_info[i].xpos;
6972     gd_yoffset = toolbutton_info[i].ypos;
6973     gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
6974     gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
6975     gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
6976
6977     if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
6978     {
6979       int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
6980
6981       getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
6982                            &deco_bitmap, &deco_x, &deco_y);
6983       deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
6984       deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
6985     }
6986
6987     gi = CreateGadget(GDI_CUSTOM_ID, id,
6988                       GDI_INFO_TEXT, toolbutton_info[i].infotext,
6989                       GDI_X, DX + GDI_ACTIVE_POS(toolbutton_info[i].x),
6990                       GDI_Y, DY + GDI_ACTIVE_POS(toolbutton_info[i].y),
6991                       GDI_WIDTH, toolbutton_info[i].width,
6992                       GDI_HEIGHT, toolbutton_info[i].height,
6993                       GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
6994                       GDI_STATE, GD_BUTTON_UNPRESSED,
6995                       GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
6996                       GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
6997                       GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
6998                       GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
6999                       GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
7000                       GDI_DECORATION_SHIFTING, 1, 1,
7001                       GDI_DIRECT_DRAW, FALSE,
7002                       GDI_EVENT_MASK, event_mask,
7003                       GDI_CALLBACK_ACTION, HandleToolButtons,
7004                       GDI_END);
7005
7006     if (gi == NULL)
7007       Error(ERR_EXIT, "cannot create gadget");
7008
7009     tool_gadget[id] = gi;
7010   }
7011 }
7012
7013 #endif
7014
7015 void FreeToolButtons()
7016 {
7017   int i;
7018
7019   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7020     FreeGadget(tool_gadget[i]);
7021 }
7022
7023 static void UnmapToolButtons()
7024 {
7025   int i;
7026
7027   for (i = 0; i < NUM_TOOL_BUTTONS; i++)
7028     UnmapGadget(tool_gadget[i]);
7029 }
7030
7031 static void HandleToolButtons(struct GadgetInfo *gi)
7032 {
7033   request_gadget_id = gi->custom_id;
7034 }
7035
7036 static struct Mapping_EM_to_RND_object
7037 {
7038   int element_em;
7039   boolean is_rnd_to_em_mapping;         /* unique mapping EM <-> RND */
7040   boolean is_backside;                  /* backside of moving element */
7041
7042   int element_rnd;
7043   int action;
7044   int direction;
7045 }
7046 em_object_mapping_list[] =
7047 {
7048   {
7049     Xblank,                             TRUE,   FALSE,
7050     EL_EMPTY,                           -1, -1
7051   },
7052   {
7053     Yacid_splash_eB,                    FALSE,  FALSE,
7054     EL_ACID_SPLASH_RIGHT,               -1, -1
7055   },
7056   {
7057     Yacid_splash_wB,                    FALSE,  FALSE,
7058     EL_ACID_SPLASH_LEFT,                -1, -1
7059   },
7060
7061 #ifdef EM_ENGINE_BAD_ROLL
7062   {
7063     Xstone_force_e,                     FALSE,  FALSE,
7064     EL_ROCK,                            -1, MV_BIT_RIGHT
7065   },
7066   {
7067     Xstone_force_w,                     FALSE,  FALSE,
7068     EL_ROCK,                            -1, MV_BIT_LEFT
7069   },
7070   {
7071     Xnut_force_e,                       FALSE,  FALSE,
7072     EL_NUT,                             -1, MV_BIT_RIGHT
7073   },
7074   {
7075     Xnut_force_w,                       FALSE,  FALSE,
7076     EL_NUT,                             -1, MV_BIT_LEFT
7077   },
7078   {
7079     Xspring_force_e,                    FALSE,  FALSE,
7080     EL_SPRING,                          -1, MV_BIT_RIGHT
7081   },
7082   {
7083     Xspring_force_w,                    FALSE,  FALSE,
7084     EL_SPRING,                          -1, MV_BIT_LEFT
7085   },
7086   {
7087     Xemerald_force_e,                   FALSE,  FALSE,
7088     EL_EMERALD,                         -1, MV_BIT_RIGHT
7089   },
7090   {
7091     Xemerald_force_w,                   FALSE,  FALSE,
7092     EL_EMERALD,                         -1, MV_BIT_LEFT
7093   },
7094   {
7095     Xdiamond_force_e,                   FALSE,  FALSE,
7096     EL_DIAMOND,                         -1, MV_BIT_RIGHT
7097   },
7098   {
7099     Xdiamond_force_w,                   FALSE,  FALSE,
7100     EL_DIAMOND,                         -1, MV_BIT_LEFT
7101   },
7102   {
7103     Xbomb_force_e,                      FALSE,  FALSE,
7104     EL_BOMB,                            -1, MV_BIT_RIGHT
7105   },
7106   {
7107     Xbomb_force_w,                      FALSE,  FALSE,
7108     EL_BOMB,                            -1, MV_BIT_LEFT
7109   },
7110 #endif  /* EM_ENGINE_BAD_ROLL */
7111
7112   {
7113     Xstone,                             TRUE,   FALSE,
7114     EL_ROCK,                            -1, -1
7115   },
7116   {
7117     Xstone_pause,                       FALSE,  FALSE,
7118     EL_ROCK,                            -1, -1
7119   },
7120   {
7121     Xstone_fall,                        FALSE,  FALSE,
7122     EL_ROCK,                            -1, -1
7123   },
7124   {
7125     Ystone_s,                           FALSE,  FALSE,
7126     EL_ROCK,                            ACTION_FALLING, -1
7127   },
7128   {
7129     Ystone_sB,                          FALSE,  TRUE,
7130     EL_ROCK,                            ACTION_FALLING, -1
7131   },
7132   {
7133     Ystone_e,                           FALSE,  FALSE,
7134     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7135   },
7136   {
7137     Ystone_eB,                          FALSE,  TRUE,
7138     EL_ROCK,                            ACTION_MOVING, MV_BIT_RIGHT
7139   },
7140   {
7141     Ystone_w,                           FALSE,  FALSE,
7142     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7143   },
7144   {
7145     Ystone_wB,                          FALSE,  TRUE,
7146     EL_ROCK,                            ACTION_MOVING, MV_BIT_LEFT
7147   },
7148   {
7149     Xnut,                               TRUE,   FALSE,
7150     EL_NUT,                             -1, -1
7151   },
7152   {
7153     Xnut_pause,                         FALSE,  FALSE,
7154     EL_NUT,                             -1, -1
7155   },
7156   {
7157     Xnut_fall,                          FALSE,  FALSE,
7158     EL_NUT,                             -1, -1
7159   },
7160   {
7161     Ynut_s,                             FALSE,  FALSE,
7162     EL_NUT,                             ACTION_FALLING, -1
7163   },
7164   {
7165     Ynut_sB,                            FALSE,  TRUE,
7166     EL_NUT,                             ACTION_FALLING, -1
7167   },
7168   {
7169     Ynut_e,                             FALSE,  FALSE,
7170     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7171   },
7172   {
7173     Ynut_eB,                            FALSE,  TRUE,
7174     EL_NUT,                             ACTION_MOVING, MV_BIT_RIGHT
7175   },
7176   {
7177     Ynut_w,                             FALSE,  FALSE,
7178     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7179   },
7180   {
7181     Ynut_wB,                            FALSE,  TRUE,
7182     EL_NUT,                             ACTION_MOVING, MV_BIT_LEFT
7183   },
7184   {
7185     Xbug_n,                             TRUE,   FALSE,
7186     EL_BUG_UP,                          -1, -1
7187   },
7188   {
7189     Xbug_e,                             TRUE,   FALSE,
7190     EL_BUG_RIGHT,                       -1, -1
7191   },
7192   {
7193     Xbug_s,                             TRUE,   FALSE,
7194     EL_BUG_DOWN,                        -1, -1
7195   },
7196   {
7197     Xbug_w,                             TRUE,   FALSE,
7198     EL_BUG_LEFT,                        -1, -1
7199   },
7200   {
7201     Xbug_gon,                           FALSE,  FALSE,
7202     EL_BUG_UP,                          -1, -1
7203   },
7204   {
7205     Xbug_goe,                           FALSE,  FALSE,
7206     EL_BUG_RIGHT,                       -1, -1
7207   },
7208   {
7209     Xbug_gos,                           FALSE,  FALSE,
7210     EL_BUG_DOWN,                        -1, -1
7211   },
7212   {
7213     Xbug_gow,                           FALSE,  FALSE,
7214     EL_BUG_LEFT,                        -1, -1
7215   },
7216   {
7217     Ybug_n,                             FALSE,  FALSE,
7218     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7219   },
7220   {
7221     Ybug_nB,                            FALSE,  TRUE,
7222     EL_BUG,                             ACTION_MOVING, MV_BIT_UP
7223   },
7224   {
7225     Ybug_e,                             FALSE,  FALSE,
7226     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7227   },
7228   {
7229     Ybug_eB,                            FALSE,  TRUE,
7230     EL_BUG,                             ACTION_MOVING, MV_BIT_RIGHT
7231   },
7232   {
7233     Ybug_s,                             FALSE,  FALSE,
7234     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7235   },
7236   {
7237     Ybug_sB,                            FALSE,  TRUE,
7238     EL_BUG,                             ACTION_MOVING, MV_BIT_DOWN
7239   },
7240   {
7241     Ybug_w,                             FALSE,  FALSE,
7242     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7243   },
7244   {
7245     Ybug_wB,                            FALSE,  TRUE,
7246     EL_BUG,                             ACTION_MOVING, MV_BIT_LEFT
7247   },
7248   {
7249     Ybug_w_n,                           FALSE,  FALSE,
7250     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7251   },
7252   {
7253     Ybug_n_e,                           FALSE,  FALSE,
7254     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7255   },
7256   {
7257     Ybug_e_s,                           FALSE,  FALSE,
7258     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7259   },
7260   {
7261     Ybug_s_w,                           FALSE,  FALSE,
7262     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7263   },
7264   {
7265     Ybug_e_n,                           FALSE,  FALSE,
7266     EL_BUG,                             ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7267   },
7268   {
7269     Ybug_s_e,                           FALSE,  FALSE,
7270     EL_BUG,                             ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7271   },
7272   {
7273     Ybug_w_s,                           FALSE,  FALSE,
7274     EL_BUG,                             ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7275   },
7276   {
7277     Ybug_n_w,                           FALSE,  FALSE,
7278     EL_BUG,                             ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7279   },
7280   {
7281     Ybug_stone,                         FALSE,  FALSE,
7282     EL_BUG,                             ACTION_SMASHED_BY_ROCK, -1
7283   },
7284   {
7285     Ybug_spring,                        FALSE,  FALSE,
7286     EL_BUG,                             ACTION_SMASHED_BY_SPRING, -1
7287   },
7288   {
7289     Xtank_n,                            TRUE,   FALSE,
7290     EL_SPACESHIP_UP,                    -1, -1
7291   },
7292   {
7293     Xtank_e,                            TRUE,   FALSE,
7294     EL_SPACESHIP_RIGHT,                 -1, -1
7295   },
7296   {
7297     Xtank_s,                            TRUE,   FALSE,
7298     EL_SPACESHIP_DOWN,                  -1, -1
7299   },
7300   {
7301     Xtank_w,                            TRUE,   FALSE,
7302     EL_SPACESHIP_LEFT,                  -1, -1
7303   },
7304   {
7305     Xtank_gon,                          FALSE,  FALSE,
7306     EL_SPACESHIP_UP,                    -1, -1
7307   },
7308   {
7309     Xtank_goe,                          FALSE,  FALSE,
7310     EL_SPACESHIP_RIGHT,                 -1, -1
7311   },
7312   {
7313     Xtank_gos,                          FALSE,  FALSE,
7314     EL_SPACESHIP_DOWN,                  -1, -1
7315   },
7316   {
7317     Xtank_gow,                          FALSE,  FALSE,
7318     EL_SPACESHIP_LEFT,                  -1, -1
7319   },
7320   {
7321     Ytank_n,                            FALSE,  FALSE,
7322     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7323   },
7324   {
7325     Ytank_nB,                           FALSE,  TRUE,
7326     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_UP
7327   },
7328   {
7329     Ytank_e,                            FALSE,  FALSE,
7330     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7331   },
7332   {
7333     Ytank_eB,                           FALSE,  TRUE,
7334     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_RIGHT
7335   },
7336   {
7337     Ytank_s,                            FALSE,  FALSE,
7338     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7339   },
7340   {
7341     Ytank_sB,                           FALSE,  TRUE,
7342     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_DOWN
7343   },
7344   {
7345     Ytank_w,                            FALSE,  FALSE,
7346     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7347   },
7348   {
7349     Ytank_wB,                           FALSE,  TRUE,
7350     EL_SPACESHIP,                       ACTION_MOVING, MV_BIT_LEFT
7351   },
7352   {
7353     Ytank_w_n,                          FALSE,  FALSE,
7354     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_UP
7355   },
7356   {
7357     Ytank_n_e,                          FALSE,  FALSE,
7358     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
7359   },
7360   {
7361     Ytank_e_s,                          FALSE,  FALSE,
7362     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
7363   },
7364   {
7365     Ytank_s_w,                          FALSE,  FALSE,
7366     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
7367   },
7368   {
7369     Ytank_e_n,                          FALSE,  FALSE,
7370     EL_SPACESHIP,                       ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
7371   },
7372   {
7373     Ytank_s_e,                          FALSE,  FALSE,
7374     EL_SPACESHIP,                       ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
7375   },
7376   {
7377     Ytank_w_s,                          FALSE,  FALSE,
7378     EL_SPACESHIP,                       ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
7379   },
7380   {
7381     Ytank_n_w,                          FALSE,  FALSE,
7382     EL_SPACESHIP,                       ACTION_TURNING_FROM_UP, MV_BIT_LEFT
7383   },
7384   {
7385     Ytank_stone,                        FALSE,  FALSE,
7386     EL_SPACESHIP,                       ACTION_SMASHED_BY_ROCK, -1
7387   },
7388   {
7389     Ytank_spring,                       FALSE,  FALSE,
7390     EL_SPACESHIP,                       ACTION_SMASHED_BY_SPRING, -1
7391   },
7392   {
7393     Xandroid,                           TRUE,   FALSE,
7394     EL_EMC_ANDROID,                     ACTION_ACTIVE, -1
7395   },
7396   {
7397     Xandroid_1_n,                       FALSE,  FALSE,
7398     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7399   },
7400   {
7401     Xandroid_2_n,                       FALSE,  FALSE,
7402     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_UP
7403   },
7404   {
7405     Xandroid_1_e,                       FALSE,  FALSE,
7406     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7407   },
7408   {
7409     Xandroid_2_e,                       FALSE,  FALSE,
7410     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_RIGHT
7411   },
7412   {
7413     Xandroid_1_w,                       FALSE,  FALSE,
7414     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7415   },
7416   {
7417     Xandroid_2_w,                       FALSE,  FALSE,
7418     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_LEFT
7419   },
7420   {
7421     Xandroid_1_s,                       FALSE,  FALSE,
7422     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7423   },
7424   {
7425     Xandroid_2_s,                       FALSE,  FALSE,
7426     EL_EMC_ANDROID,                     ACTION_ACTIVE, MV_BIT_DOWN
7427   },
7428   {
7429     Yandroid_n,                         FALSE,  FALSE,
7430     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7431   },
7432   {
7433     Yandroid_nB,                        FALSE,  TRUE,
7434     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_UP
7435   },
7436   {
7437     Yandroid_ne,                        FALSE,  FALSE,
7438     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPRIGHT
7439   },
7440   {
7441     Yandroid_neB,                       FALSE,  TRUE,
7442     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPRIGHT
7443   },
7444   {
7445     Yandroid_e,                         FALSE,  FALSE,
7446     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7447   },
7448   {
7449     Yandroid_eB,                        FALSE,  TRUE,
7450     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_RIGHT
7451   },
7452   {
7453     Yandroid_se,                        FALSE,  FALSE,
7454     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNRIGHT
7455   },
7456   {
7457     Yandroid_seB,                       FALSE,  TRUE,
7458     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNRIGHT
7459   },
7460   {
7461     Yandroid_s,                         FALSE,  FALSE,
7462     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7463   },
7464   {
7465     Yandroid_sB,                        FALSE,  TRUE,
7466     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_DOWN
7467   },
7468   {
7469     Yandroid_sw,                        FALSE,  FALSE,
7470     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_DOWNLEFT
7471   },
7472   {
7473     Yandroid_swB,                       FALSE,  TRUE,
7474     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_DOWNLEFT
7475   },
7476   {
7477     Yandroid_w,                         FALSE,  FALSE,
7478     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7479   },
7480   {
7481     Yandroid_wB,                        FALSE,  TRUE,
7482     EL_EMC_ANDROID,                     ACTION_MOVING, MV_BIT_LEFT
7483   },
7484   {
7485     Yandroid_nw,                        FALSE,  FALSE,
7486     EL_EMC_ANDROID,                     ACTION_GROWING, MV_BIT_UPLEFT
7487   },
7488   {
7489     Yandroid_nwB,                       FALSE,  TRUE,
7490     EL_EMC_ANDROID,                     ACTION_SHRINKING, MV_BIT_UPLEFT
7491   },
7492   {
7493     Xspring,                            TRUE,   FALSE,
7494     EL_SPRING,                          -1, -1
7495   },
7496   {
7497     Xspring_pause,                      FALSE,  FALSE,
7498     EL_SPRING,                          -1, -1
7499   },
7500   {
7501     Xspring_e,                          FALSE,  FALSE,
7502     EL_SPRING,                          -1, -1
7503   },
7504   {
7505     Xspring_w,                          FALSE,  FALSE,
7506     EL_SPRING,                          -1, -1
7507   },
7508   {
7509     Xspring_fall,                       FALSE,  FALSE,
7510     EL_SPRING,                          -1, -1
7511   },
7512   {
7513     Yspring_s,                          FALSE,  FALSE,
7514     EL_SPRING,                          ACTION_FALLING, -1
7515   },
7516   {
7517     Yspring_sB,                         FALSE,  TRUE,
7518     EL_SPRING,                          ACTION_FALLING, -1
7519   },
7520   {
7521     Yspring_e,                          FALSE,  FALSE,
7522     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7523   },
7524   {
7525     Yspring_eB,                         FALSE,  TRUE,
7526     EL_SPRING,                          ACTION_MOVING, MV_BIT_RIGHT
7527   },
7528   {
7529     Yspring_w,                          FALSE,  FALSE,
7530     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7531   },
7532   {
7533     Yspring_wB,                         FALSE,  TRUE,
7534     EL_SPRING,                          ACTION_MOVING, MV_BIT_LEFT
7535   },
7536   {
7537     Yspring_kill_e,                     FALSE,  FALSE,
7538     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7539   },
7540   {
7541     Yspring_kill_eB,                    FALSE,  TRUE,
7542     EL_SPRING,                          ACTION_EATING, MV_BIT_RIGHT
7543   },
7544   {
7545     Yspring_kill_w,                     FALSE,  FALSE,
7546     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7547   },
7548   {
7549     Yspring_kill_wB,                    FALSE,  TRUE,
7550     EL_SPRING,                          ACTION_EATING, MV_BIT_LEFT
7551   },
7552   {
7553     Xeater_n,                           TRUE,   FALSE,
7554     EL_YAMYAM_UP,                       -1, -1
7555   },
7556   {
7557     Xeater_e,                           TRUE,   FALSE,
7558     EL_YAMYAM_RIGHT,                    -1, -1
7559   },
7560   {
7561     Xeater_w,                           TRUE,   FALSE,
7562     EL_YAMYAM_LEFT,                     -1, -1
7563   },
7564   {
7565     Xeater_s,                           TRUE,   FALSE,
7566     EL_YAMYAM_DOWN,                     -1, -1
7567   },
7568   {
7569     Yeater_n,                           FALSE,  FALSE,
7570     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7571   },
7572   {
7573     Yeater_nB,                          FALSE,  TRUE,
7574     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_UP
7575   },
7576   {
7577     Yeater_e,                           FALSE,  FALSE,
7578     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7579   },
7580   {
7581     Yeater_eB,                          FALSE,  TRUE,
7582     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_RIGHT
7583   },
7584   {
7585     Yeater_s,                           FALSE,  FALSE,
7586     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7587   },
7588   {
7589     Yeater_sB,                          FALSE,  TRUE,
7590     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_DOWN
7591   },
7592   {
7593     Yeater_w,                           FALSE,  FALSE,
7594     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7595   },
7596   {
7597     Yeater_wB,                          FALSE,  TRUE,
7598     EL_YAMYAM,                          ACTION_MOVING, MV_BIT_LEFT
7599   },
7600   {
7601     Yeater_stone,                       FALSE,  FALSE,
7602     EL_YAMYAM,                          ACTION_SMASHED_BY_ROCK, -1
7603   },
7604   {
7605     Yeater_spring,                      FALSE,  FALSE,
7606     EL_YAMYAM,                          ACTION_SMASHED_BY_SPRING, -1
7607   },
7608   {
7609     Xalien,                             TRUE,   FALSE,
7610     EL_ROBOT,                           -1, -1
7611   },
7612   {
7613     Xalien_pause,                       FALSE,  FALSE,
7614     EL_ROBOT,                           -1, -1
7615   },
7616   {
7617     Yalien_n,                           FALSE,  FALSE,
7618     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7619   },
7620   {
7621     Yalien_nB,                          FALSE,  TRUE,
7622     EL_ROBOT,                           ACTION_MOVING, MV_BIT_UP
7623   },
7624   {
7625     Yalien_e,                           FALSE,  FALSE,
7626     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7627   },
7628   {
7629     Yalien_eB,                          FALSE,  TRUE,
7630     EL_ROBOT,                           ACTION_MOVING, MV_BIT_RIGHT
7631   },
7632   {
7633     Yalien_s,                           FALSE,  FALSE,
7634     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7635   },
7636   {
7637     Yalien_sB,                          FALSE,  TRUE,
7638     EL_ROBOT,                           ACTION_MOVING, MV_BIT_DOWN
7639   },
7640   {
7641     Yalien_w,                           FALSE,  FALSE,
7642     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7643   },
7644   {
7645     Yalien_wB,                          FALSE,  TRUE,
7646     EL_ROBOT,                           ACTION_MOVING, MV_BIT_LEFT
7647   },
7648   {
7649     Yalien_stone,                       FALSE,  FALSE,
7650     EL_ROBOT,                           ACTION_SMASHED_BY_ROCK, -1
7651   },
7652   {
7653     Yalien_spring,                      FALSE,  FALSE,
7654     EL_ROBOT,                           ACTION_SMASHED_BY_SPRING, -1
7655   },
7656   {
7657     Xemerald,                           TRUE,   FALSE,
7658     EL_EMERALD,                         -1, -1
7659   },
7660   {
7661     Xemerald_pause,                     FALSE,  FALSE,
7662     EL_EMERALD,                         -1, -1
7663   },
7664   {
7665     Xemerald_fall,                      FALSE,  FALSE,
7666     EL_EMERALD,                         -1, -1
7667   },
7668   {
7669     Xemerald_shine,                     FALSE,  FALSE,
7670     EL_EMERALD,                         ACTION_TWINKLING, -1
7671   },
7672   {
7673     Yemerald_s,                         FALSE,  FALSE,
7674     EL_EMERALD,                         ACTION_FALLING, -1
7675   },
7676   {
7677     Yemerald_sB,                        FALSE,  TRUE,
7678     EL_EMERALD,                         ACTION_FALLING, -1
7679   },
7680   {
7681     Yemerald_e,                         FALSE,  FALSE,
7682     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7683   },
7684   {
7685     Yemerald_eB,                        FALSE,  TRUE,
7686     EL_EMERALD,                         ACTION_MOVING, MV_BIT_RIGHT
7687   },
7688   {
7689     Yemerald_w,                         FALSE,  FALSE,
7690     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7691   },
7692   {
7693     Yemerald_wB,                        FALSE,  TRUE,
7694     EL_EMERALD,                         ACTION_MOVING, MV_BIT_LEFT
7695   },
7696   {
7697     Yemerald_eat,                       FALSE,  FALSE,
7698     EL_EMERALD,                         ACTION_COLLECTING, -1
7699   },
7700   {
7701     Yemerald_stone,                     FALSE,  FALSE,
7702     EL_NUT,                             ACTION_BREAKING, -1
7703   },
7704   {
7705     Xdiamond,                           TRUE,   FALSE,
7706     EL_DIAMOND,                         -1, -1
7707   },
7708   {
7709     Xdiamond_pause,                     FALSE,  FALSE,
7710     EL_DIAMOND,                         -1, -1
7711   },
7712   {
7713     Xdiamond_fall,                      FALSE,  FALSE,
7714     EL_DIAMOND,                         -1, -1
7715   },
7716   {
7717     Xdiamond_shine,                     FALSE,  FALSE,
7718     EL_DIAMOND,                         ACTION_TWINKLING, -1
7719   },
7720   {
7721     Ydiamond_s,                         FALSE,  FALSE,
7722     EL_DIAMOND,                         ACTION_FALLING, -1
7723   },
7724   {
7725     Ydiamond_sB,                        FALSE,  TRUE,
7726     EL_DIAMOND,                         ACTION_FALLING, -1
7727   },
7728   {
7729     Ydiamond_e,                         FALSE,  FALSE,
7730     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7731   },
7732   {
7733     Ydiamond_eB,                        FALSE,  TRUE,
7734     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_RIGHT
7735   },
7736   {
7737     Ydiamond_w,                         FALSE,  FALSE,
7738     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7739   },
7740   {
7741     Ydiamond_wB,                        FALSE,  TRUE,
7742     EL_DIAMOND,                         ACTION_MOVING, MV_BIT_LEFT
7743   },
7744   {
7745     Ydiamond_eat,                       FALSE,  FALSE,
7746     EL_DIAMOND,                         ACTION_COLLECTING, -1
7747   },
7748   {
7749     Ydiamond_stone,                     FALSE,  FALSE,
7750     EL_DIAMOND,                         ACTION_SMASHED_BY_ROCK, -1
7751   },
7752   {
7753     Xdrip_fall,                         TRUE,   FALSE,
7754     EL_AMOEBA_DROP,                     -1, -1
7755   },
7756   {
7757     Xdrip_stretch,                      FALSE,  FALSE,
7758     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7759   },
7760   {
7761     Xdrip_stretchB,                     FALSE,  TRUE,
7762     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7763   },
7764   {
7765     Xdrip_eat,                          FALSE,  FALSE,
7766     EL_AMOEBA_DROP,                     ACTION_GROWING, -1
7767   },
7768   {
7769     Ydrip_s1,                           FALSE,  FALSE,
7770     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7771   },
7772   {
7773     Ydrip_s1B,                          FALSE,  TRUE,
7774     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7775   },
7776   {
7777     Ydrip_s2,                           FALSE,  FALSE,
7778     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7779   },
7780   {
7781     Ydrip_s2B,                          FALSE,  TRUE,
7782     EL_AMOEBA_DROP,                     ACTION_FALLING, -1
7783   },
7784   {
7785     Xbomb,                              TRUE,   FALSE,
7786     EL_BOMB,                            -1, -1
7787   },
7788   {
7789     Xbomb_pause,                        FALSE,  FALSE,
7790     EL_BOMB,                            -1, -1
7791   },
7792   {
7793     Xbomb_fall,                         FALSE,  FALSE,
7794     EL_BOMB,                            -1, -1
7795   },
7796   {
7797     Ybomb_s,                            FALSE,  FALSE,
7798     EL_BOMB,                            ACTION_FALLING, -1
7799   },
7800   {
7801     Ybomb_sB,                           FALSE,  TRUE,
7802     EL_BOMB,                            ACTION_FALLING, -1
7803   },
7804   {
7805     Ybomb_e,                            FALSE,  FALSE,
7806     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7807   },
7808   {
7809     Ybomb_eB,                           FALSE,  TRUE,
7810     EL_BOMB,                            ACTION_MOVING, MV_BIT_RIGHT
7811   },
7812   {
7813     Ybomb_w,                            FALSE,  FALSE,
7814     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7815   },
7816   {
7817     Ybomb_wB,                           FALSE,  TRUE,
7818     EL_BOMB,                            ACTION_MOVING, MV_BIT_LEFT
7819   },
7820   {
7821     Ybomb_eat,                          FALSE,  FALSE,
7822     EL_BOMB,                            ACTION_ACTIVATING, -1
7823   },
7824   {
7825     Xballoon,                           TRUE,   FALSE,
7826     EL_BALLOON,                         -1, -1
7827   },
7828   {
7829     Yballoon_n,                         FALSE,  FALSE,
7830     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7831   },
7832   {
7833     Yballoon_nB,                        FALSE,  TRUE,
7834     EL_BALLOON,                         ACTION_MOVING, MV_BIT_UP
7835   },
7836   {
7837     Yballoon_e,                         FALSE,  FALSE,
7838     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
7839   },
7840   {
7841     Yballoon_eB,                        FALSE,  TRUE,
7842     EL_BALLOON,                         ACTION_MOVING, MV_BIT_RIGHT
7843   },
7844   {
7845     Yballoon_s,                         FALSE,  FALSE,
7846     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
7847   },
7848   {
7849     Yballoon_sB,                        FALSE,  TRUE,
7850     EL_BALLOON,                         ACTION_MOVING, MV_BIT_DOWN
7851   },
7852   {
7853     Yballoon_w,                         FALSE,  FALSE,
7854     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
7855   },
7856   {
7857     Yballoon_wB,                        FALSE,  TRUE,
7858     EL_BALLOON,                         ACTION_MOVING, MV_BIT_LEFT
7859   },
7860   {
7861     Xgrass,                             TRUE,   FALSE,
7862     EL_EMC_GRASS,                       -1, -1
7863   },
7864   {
7865     Ygrass_nB,                          FALSE,  FALSE,
7866     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_UP
7867   },
7868   {
7869     Ygrass_eB,                          FALSE,  FALSE,
7870     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_RIGHT
7871   },
7872   {
7873     Ygrass_sB,                          FALSE,  FALSE,
7874     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_DOWN
7875   },
7876   {
7877     Ygrass_wB,                          FALSE,  FALSE,
7878     EL_EMC_GRASS,                       ACTION_DIGGING, MV_BIT_LEFT
7879   },
7880   {
7881     Xdirt,                              TRUE,   FALSE,
7882     EL_SAND,                            -1, -1
7883   },
7884   {
7885     Ydirt_nB,                           FALSE,  FALSE,
7886     EL_SAND,                            ACTION_DIGGING, MV_BIT_UP
7887   },
7888   {
7889     Ydirt_eB,                           FALSE,  FALSE,
7890     EL_SAND,                            ACTION_DIGGING, MV_BIT_RIGHT
7891   },
7892   {
7893     Ydirt_sB,                           FALSE,  FALSE,
7894     EL_SAND,                            ACTION_DIGGING, MV_BIT_DOWN
7895   },
7896   {
7897     Ydirt_wB,                           FALSE,  FALSE,
7898     EL_SAND,                            ACTION_DIGGING, MV_BIT_LEFT
7899   },
7900   {
7901     Xacid_ne,                           TRUE,   FALSE,
7902     EL_ACID_POOL_TOPRIGHT,              -1, -1
7903   },
7904   {
7905     Xacid_se,                           TRUE,   FALSE,
7906     EL_ACID_POOL_BOTTOMRIGHT,           -1, -1
7907   },
7908   {
7909     Xacid_s,                            TRUE,   FALSE,
7910     EL_ACID_POOL_BOTTOM,                -1, -1
7911   },
7912   {
7913     Xacid_sw,                           TRUE,   FALSE,
7914     EL_ACID_POOL_BOTTOMLEFT,            -1, -1
7915   },
7916   {
7917     Xacid_nw,                           TRUE,   FALSE,
7918     EL_ACID_POOL_TOPLEFT,               -1, -1
7919   },
7920   {
7921     Xacid_1,                            TRUE,   FALSE,
7922     EL_ACID,                            -1, -1
7923   },
7924   {
7925     Xacid_2,                            FALSE,  FALSE,
7926     EL_ACID,                            -1, -1
7927   },
7928   {
7929     Xacid_3,                            FALSE,  FALSE,
7930     EL_ACID,                            -1, -1
7931   },
7932   {
7933     Xacid_4,                            FALSE,  FALSE,
7934     EL_ACID,                            -1, -1
7935   },
7936   {
7937     Xacid_5,                            FALSE,  FALSE,
7938     EL_ACID,                            -1, -1
7939   },
7940   {
7941     Xacid_6,                            FALSE,  FALSE,
7942     EL_ACID,                            -1, -1
7943   },
7944   {
7945     Xacid_7,                            FALSE,  FALSE,
7946     EL_ACID,                            -1, -1
7947   },
7948   {
7949     Xacid_8,                            FALSE,  FALSE,
7950     EL_ACID,                            -1, -1
7951   },
7952   {
7953     Xball_1,                            TRUE,   FALSE,
7954     EL_EMC_MAGIC_BALL,                  -1, -1
7955   },
7956   {
7957     Xball_1B,                           FALSE,  FALSE,
7958     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7959   },
7960   {
7961     Xball_2,                            FALSE,  FALSE,
7962     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7963   },
7964   {
7965     Xball_2B,                           FALSE,  FALSE,
7966     EL_EMC_MAGIC_BALL,                  ACTION_ACTIVE, -1
7967   },
7968   {
7969     Yball_eat,                          FALSE,  FALSE,
7970     EL_EMC_MAGIC_BALL,                  ACTION_DROPPING, -1
7971   },
7972   {
7973     Ykey_1_eat,                         FALSE,  FALSE,
7974     EL_EM_KEY_1,                        ACTION_COLLECTING, -1
7975   },
7976   {
7977     Ykey_2_eat,                         FALSE,  FALSE,
7978     EL_EM_KEY_2,                        ACTION_COLLECTING, -1
7979   },
7980   {
7981     Ykey_3_eat,                         FALSE,  FALSE,
7982     EL_EM_KEY_3,                        ACTION_COLLECTING, -1
7983   },
7984   {
7985     Ykey_4_eat,                         FALSE,  FALSE,
7986     EL_EM_KEY_4,                        ACTION_COLLECTING, -1
7987   },
7988   {
7989     Ykey_5_eat,                         FALSE,  FALSE,
7990     EL_EMC_KEY_5,                       ACTION_COLLECTING, -1
7991   },
7992   {
7993     Ykey_6_eat,                         FALSE,  FALSE,
7994     EL_EMC_KEY_6,                       ACTION_COLLECTING, -1
7995   },
7996   {
7997     Ykey_7_eat,                         FALSE,  FALSE,
7998     EL_EMC_KEY_7,                       ACTION_COLLECTING, -1
7999   },
8000   {
8001     Ykey_8_eat,                         FALSE,  FALSE,
8002     EL_EMC_KEY_8,                       ACTION_COLLECTING, -1
8003   },
8004   {
8005     Ylenses_eat,                        FALSE,  FALSE,
8006     EL_EMC_LENSES,                      ACTION_COLLECTING, -1
8007   },
8008   {
8009     Ymagnify_eat,                       FALSE,  FALSE,
8010     EL_EMC_MAGNIFIER,                   ACTION_COLLECTING, -1
8011   },
8012   {
8013     Ygrass_eat,                         FALSE,  FALSE,
8014     EL_EMC_GRASS,                       ACTION_SNAPPING, -1
8015   },
8016   {
8017     Ydirt_eat,                          FALSE,  FALSE,
8018     EL_SAND,                            ACTION_SNAPPING, -1
8019   },
8020   {
8021     Xgrow_ns,                           TRUE,   FALSE,
8022     EL_EXPANDABLE_WALL_VERTICAL,        -1, -1
8023   },
8024   {
8025     Ygrow_ns_eat,                       FALSE,  FALSE,
8026     EL_EXPANDABLE_WALL_VERTICAL,        ACTION_GROWING, -1
8027   },
8028   {
8029     Xgrow_ew,                           TRUE,   FALSE,
8030     EL_EXPANDABLE_WALL_HORIZONTAL,      -1, -1
8031   },
8032   {
8033     Ygrow_ew_eat,                       FALSE,  FALSE,
8034     EL_EXPANDABLE_WALL_HORIZONTAL,      ACTION_GROWING, -1
8035   },
8036   {
8037     Xwonderwall,                        TRUE,   FALSE,
8038     EL_MAGIC_WALL,                      -1, -1
8039   },
8040   {
8041     XwonderwallB,                       FALSE,  FALSE,
8042     EL_MAGIC_WALL,                      ACTION_ACTIVE, -1
8043   },
8044   {
8045     Xamoeba_1,                          TRUE,   FALSE,
8046     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8047   },
8048   {
8049     Xamoeba_2,                          FALSE,  FALSE,
8050     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8051   },
8052   {
8053     Xamoeba_3,                          FALSE,  FALSE,
8054     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8055   },
8056   {
8057     Xamoeba_4,                          FALSE,  FALSE,
8058     EL_AMOEBA_DRY,                      ACTION_OTHER, -1
8059   },
8060   {
8061     Xamoeba_5,                          TRUE,   FALSE,
8062     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8063   },
8064   {
8065     Xamoeba_6,                          FALSE,  FALSE,
8066     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8067   },
8068   {
8069     Xamoeba_7,                          FALSE,  FALSE,
8070     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8071   },
8072   {
8073     Xamoeba_8,                          FALSE,  FALSE,
8074     EL_AMOEBA_WET,                      ACTION_OTHER, -1
8075   },
8076   {
8077     Xdoor_1,                            TRUE,   FALSE,
8078     EL_EM_GATE_1,                       -1, -1
8079   },
8080   {
8081     Xdoor_2,                            TRUE,   FALSE,
8082     EL_EM_GATE_2,                       -1, -1
8083   },
8084   {
8085     Xdoor_3,                            TRUE,   FALSE,
8086     EL_EM_GATE_3,                       -1, -1
8087   },
8088   {
8089     Xdoor_4,                            TRUE,   FALSE,
8090     EL_EM_GATE_4,                       -1, -1
8091   },
8092   {
8093     Xdoor_5,                            TRUE,   FALSE,
8094     EL_EMC_GATE_5,                      -1, -1
8095   },
8096   {
8097     Xdoor_6,                            TRUE,   FALSE,
8098     EL_EMC_GATE_6,                      -1, -1
8099   },
8100   {
8101     Xdoor_7,                            TRUE,   FALSE,
8102     EL_EMC_GATE_7,                      -1, -1
8103   },
8104   {
8105     Xdoor_8,                            TRUE,   FALSE,
8106     EL_EMC_GATE_8,                      -1, -1
8107   },
8108   {
8109     Xkey_1,                             TRUE,   FALSE,
8110     EL_EM_KEY_1,                        -1, -1
8111   },
8112   {
8113     Xkey_2,                             TRUE,   FALSE,
8114     EL_EM_KEY_2,                        -1, -1
8115   },
8116   {
8117     Xkey_3,                             TRUE,   FALSE,
8118     EL_EM_KEY_3,                        -1, -1
8119   },
8120   {
8121     Xkey_4,                             TRUE,   FALSE,
8122     EL_EM_KEY_4,                        -1, -1
8123   },
8124   {
8125     Xkey_5,                             TRUE,   FALSE,
8126     EL_EMC_KEY_5,                       -1, -1
8127   },
8128   {
8129     Xkey_6,                             TRUE,   FALSE,
8130     EL_EMC_KEY_6,                       -1, -1
8131   },
8132   {
8133     Xkey_7,                             TRUE,   FALSE,
8134     EL_EMC_KEY_7,                       -1, -1
8135   },
8136   {
8137     Xkey_8,                             TRUE,   FALSE,
8138     EL_EMC_KEY_8,                       -1, -1
8139   },
8140   {
8141     Xwind_n,                            TRUE,   FALSE,
8142     EL_BALLOON_SWITCH_UP,               -1, -1
8143   },
8144   {
8145     Xwind_e,                            TRUE,   FALSE,
8146     EL_BALLOON_SWITCH_RIGHT,            -1, -1
8147   },
8148   {
8149     Xwind_s,                            TRUE,   FALSE,
8150     EL_BALLOON_SWITCH_DOWN,             -1, -1
8151   },
8152   {
8153     Xwind_w,                            TRUE,   FALSE,
8154     EL_BALLOON_SWITCH_LEFT,             -1, -1
8155   },
8156   {
8157     Xwind_nesw,                         TRUE,   FALSE,
8158     EL_BALLOON_SWITCH_ANY,              -1, -1
8159   },
8160   {
8161     Xwind_stop,                         TRUE,   FALSE,
8162     EL_BALLOON_SWITCH_NONE,             -1, -1
8163   },
8164   {
8165     Xexit,                              TRUE,   FALSE,
8166     EL_EM_EXIT_CLOSED,                  -1, -1
8167   },
8168   {
8169     Xexit_1,                            TRUE,   FALSE,
8170     EL_EM_EXIT_OPEN,                    -1, -1
8171   },
8172   {
8173     Xexit_2,                            FALSE,  FALSE,
8174     EL_EM_EXIT_OPEN,                    -1, -1
8175   },
8176   {
8177     Xexit_3,                            FALSE,  FALSE,
8178     EL_EM_EXIT_OPEN,                    -1, -1
8179   },
8180   {
8181     Xdynamite,                          TRUE,   FALSE,
8182     EL_EM_DYNAMITE,                     -1, -1
8183   },
8184   {
8185     Ydynamite_eat,                      FALSE,  FALSE,
8186     EL_EM_DYNAMITE,                     ACTION_COLLECTING, -1
8187   },
8188   {
8189     Xdynamite_1,                        TRUE,   FALSE,
8190     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8191   },
8192   {
8193     Xdynamite_2,                        FALSE,  FALSE,
8194     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8195   },
8196   {
8197     Xdynamite_3,                        FALSE,  FALSE,
8198     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8199   },
8200   {
8201     Xdynamite_4,                        FALSE,  FALSE,
8202     EL_EM_DYNAMITE_ACTIVE,              -1, -1
8203   },
8204   {
8205     Xbumper,                            TRUE,   FALSE,
8206     EL_EMC_SPRING_BUMPER,               -1, -1
8207   },
8208   {
8209     XbumperB,                           FALSE,  FALSE,
8210     EL_EMC_SPRING_BUMPER,               ACTION_ACTIVE, -1
8211   },
8212   {
8213     Xwheel,                             TRUE,   FALSE,
8214     EL_ROBOT_WHEEL,                     -1, -1
8215   },
8216   {
8217     XwheelB,                            FALSE,  FALSE,
8218     EL_ROBOT_WHEEL,                     ACTION_ACTIVE, -1
8219   },
8220   {
8221     Xswitch,                            TRUE,   FALSE,
8222     EL_EMC_MAGIC_BALL_SWITCH,           -1, -1
8223   },
8224   {
8225     XswitchB,                           FALSE,  FALSE,
8226     EL_EMC_MAGIC_BALL_SWITCH,           ACTION_ACTIVE, -1
8227   },
8228   {
8229     Xsand,                              TRUE,   FALSE,
8230     EL_QUICKSAND_EMPTY,                 -1, -1
8231   },
8232   {
8233     Xsand_stone,                        TRUE,   FALSE,
8234     EL_QUICKSAND_FULL,                  -1, -1
8235   },
8236   {
8237     Xsand_stonein_1,                    FALSE,  TRUE,
8238     EL_ROCK,                            ACTION_FILLING, -1
8239   },
8240   {
8241     Xsand_stonein_2,                    FALSE,  TRUE,
8242     EL_ROCK,                            ACTION_FILLING, -1
8243   },
8244   {
8245     Xsand_stonein_3,                    FALSE,  TRUE,
8246     EL_ROCK,                            ACTION_FILLING, -1
8247   },
8248   {
8249     Xsand_stonein_4,                    FALSE,  TRUE,
8250     EL_ROCK,                            ACTION_FILLING, -1
8251   },
8252 #if 1
8253   {
8254     Xsand_stonesand_1,                  FALSE,  FALSE,
8255     EL_QUICKSAND_EMPTYING,              -1, -1
8256   },
8257   {
8258     Xsand_stonesand_2,                  FALSE,  FALSE,
8259     EL_QUICKSAND_EMPTYING,              -1, -1
8260   },
8261   {
8262     Xsand_stonesand_3,                  FALSE,  FALSE,
8263     EL_QUICKSAND_EMPTYING,              -1, -1
8264   },
8265   {
8266     Xsand_stonesand_4,                  FALSE,  FALSE,
8267     EL_QUICKSAND_EMPTYING,              -1, -1
8268   },
8269   {
8270     Xsand_stonesand_quickout_1,         FALSE,  FALSE,
8271     EL_QUICKSAND_EMPTYING,              -1, -1
8272   },
8273   {
8274     Xsand_stonesand_quickout_2,         FALSE,  FALSE,
8275     EL_QUICKSAND_EMPTYING,              -1, -1
8276   },
8277 #else
8278   {
8279     Xsand_stonesand_1,                  FALSE,  FALSE,
8280     EL_QUICKSAND_FULL,                  -1, -1
8281   },
8282   {
8283     Xsand_stonesand_2,                  FALSE,  FALSE,
8284     EL_QUICKSAND_FULL,                  -1, -1
8285   },
8286   {
8287     Xsand_stonesand_3,                  FALSE,  FALSE,
8288     EL_QUICKSAND_FULL,                  -1, -1
8289   },
8290   {
8291     Xsand_stonesand_4,                  FALSE,  FALSE,
8292     EL_QUICKSAND_FULL,                  -1, -1
8293   },
8294 #endif
8295   {
8296     Xsand_stoneout_1,                   FALSE,  FALSE,
8297     EL_ROCK,                            ACTION_EMPTYING, -1
8298   },
8299   {
8300     Xsand_stoneout_2,                   FALSE,  FALSE,
8301     EL_ROCK,                            ACTION_EMPTYING, -1
8302   },
8303 #if 1
8304   {
8305     Xsand_sandstone_1,                  FALSE,  FALSE,
8306     EL_QUICKSAND_FILLING,               -1, -1
8307   },
8308   {
8309     Xsand_sandstone_2,                  FALSE,  FALSE,
8310     EL_QUICKSAND_FILLING,               -1, -1
8311   },
8312   {
8313     Xsand_sandstone_3,                  FALSE,  FALSE,
8314     EL_QUICKSAND_FILLING,               -1, -1
8315   },
8316   {
8317     Xsand_sandstone_4,                  FALSE,  FALSE,
8318     EL_QUICKSAND_FILLING,               -1, -1
8319   },
8320 #else
8321   {
8322     Xsand_sandstone_1,                  FALSE,  FALSE,
8323     EL_QUICKSAND_FULL,                  -1, -1
8324   },
8325   {
8326     Xsand_sandstone_2,                  FALSE,  FALSE,
8327     EL_QUICKSAND_FULL,                  -1, -1
8328   },
8329   {
8330     Xsand_sandstone_3,                  FALSE,  FALSE,
8331     EL_QUICKSAND_FULL,                  -1, -1
8332   },
8333   {
8334     Xsand_sandstone_4,                  FALSE,  FALSE,
8335     EL_QUICKSAND_FULL,                  -1, -1
8336   },
8337 #endif
8338   {
8339     Xplant,                             TRUE,   FALSE,
8340     EL_EMC_PLANT,                       -1, -1
8341   },
8342   {
8343     Yplant,                             FALSE,  FALSE,
8344     EL_EMC_PLANT,                       -1, -1
8345   },
8346   {
8347     Xlenses,                            TRUE,   FALSE,
8348     EL_EMC_LENSES,                      -1, -1
8349   },
8350   {
8351     Xmagnify,                           TRUE,   FALSE,
8352     EL_EMC_MAGNIFIER,                   -1, -1
8353   },
8354   {
8355     Xdripper,                           TRUE,   FALSE,
8356     EL_EMC_DRIPPER,                     -1, -1
8357   },
8358   {
8359     XdripperB,                          FALSE,  FALSE,
8360     EL_EMC_DRIPPER,                     ACTION_ACTIVE, -1
8361   },
8362   {
8363     Xfake_blank,                        TRUE,   FALSE,
8364     EL_INVISIBLE_WALL,                  -1, -1
8365   },
8366   {
8367     Xfake_blankB,                       FALSE,  FALSE,
8368     EL_INVISIBLE_WALL,                  ACTION_ACTIVE, -1
8369   },
8370   {
8371     Xfake_grass,                        TRUE,   FALSE,
8372     EL_EMC_FAKE_GRASS,                  -1, -1
8373   },
8374   {
8375     Xfake_grassB,                       FALSE,  FALSE,
8376     EL_EMC_FAKE_GRASS,                  ACTION_ACTIVE, -1
8377   },
8378   {
8379     Xfake_door_1,                       TRUE,   FALSE,
8380     EL_EM_GATE_1_GRAY,                  -1, -1
8381   },
8382   {
8383     Xfake_door_2,                       TRUE,   FALSE,
8384     EL_EM_GATE_2_GRAY,                  -1, -1
8385   },
8386   {
8387     Xfake_door_3,                       TRUE,   FALSE,
8388     EL_EM_GATE_3_GRAY,                  -1, -1
8389   },
8390   {
8391     Xfake_door_4,                       TRUE,   FALSE,
8392     EL_EM_GATE_4_GRAY,                  -1, -1
8393   },
8394   {
8395     Xfake_door_5,                       TRUE,   FALSE,
8396     EL_EMC_GATE_5_GRAY,                 -1, -1
8397   },
8398   {
8399     Xfake_door_6,                       TRUE,   FALSE,
8400     EL_EMC_GATE_6_GRAY,                 -1, -1
8401   },
8402   {
8403     Xfake_door_7,                       TRUE,   FALSE,
8404     EL_EMC_GATE_7_GRAY,                 -1, -1
8405   },
8406   {
8407     Xfake_door_8,                       TRUE,   FALSE,
8408     EL_EMC_GATE_8_GRAY,                 -1, -1
8409   },
8410   {
8411     Xfake_acid_1,                       TRUE,   FALSE,
8412     EL_EMC_FAKE_ACID,                   -1, -1
8413   },
8414   {
8415     Xfake_acid_2,                       FALSE,  FALSE,
8416     EL_EMC_FAKE_ACID,                   -1, -1
8417   },
8418   {
8419     Xfake_acid_3,                       FALSE,  FALSE,
8420     EL_EMC_FAKE_ACID,                   -1, -1
8421   },
8422   {
8423     Xfake_acid_4,                       FALSE,  FALSE,
8424     EL_EMC_FAKE_ACID,                   -1, -1
8425   },
8426   {
8427     Xfake_acid_5,                       FALSE,  FALSE,
8428     EL_EMC_FAKE_ACID,                   -1, -1
8429   },
8430   {
8431     Xfake_acid_6,                       FALSE,  FALSE,
8432     EL_EMC_FAKE_ACID,                   -1, -1
8433   },
8434   {
8435     Xfake_acid_7,                       FALSE,  FALSE,
8436     EL_EMC_FAKE_ACID,                   -1, -1
8437   },
8438   {
8439     Xfake_acid_8,                       FALSE,  FALSE,
8440     EL_EMC_FAKE_ACID,                   -1, -1
8441   },
8442   {
8443     Xsteel_1,                           TRUE,   FALSE,
8444     EL_STEELWALL,                       -1, -1
8445   },
8446   {
8447     Xsteel_2,                           TRUE,   FALSE,
8448     EL_EMC_STEELWALL_2,                 -1, -1
8449   },
8450   {
8451     Xsteel_3,                           TRUE,   FALSE,
8452     EL_EMC_STEELWALL_3,                 -1, -1
8453   },
8454   {
8455     Xsteel_4,                           TRUE,   FALSE,
8456     EL_EMC_STEELWALL_4,                 -1, -1
8457   },
8458   {
8459     Xwall_1,                            TRUE,   FALSE,
8460     EL_WALL,                            -1, -1
8461   },
8462   {
8463     Xwall_2,                            TRUE,   FALSE,
8464     EL_EMC_WALL_14,                     -1, -1
8465   },
8466   {
8467     Xwall_3,                            TRUE,   FALSE,
8468     EL_EMC_WALL_15,                     -1, -1
8469   },
8470   {
8471     Xwall_4,                            TRUE,   FALSE,
8472     EL_EMC_WALL_16,                     -1, -1
8473   },
8474   {
8475     Xround_wall_1,                      TRUE,   FALSE,
8476     EL_WALL_SLIPPERY,                   -1, -1
8477   },
8478   {
8479     Xround_wall_2,                      TRUE,   FALSE,
8480     EL_EMC_WALL_SLIPPERY_2,             -1, -1
8481   },
8482   {
8483     Xround_wall_3,                      TRUE,   FALSE,
8484     EL_EMC_WALL_SLIPPERY_3,             -1, -1
8485   },
8486   {
8487     Xround_wall_4,                      TRUE,   FALSE,
8488     EL_EMC_WALL_SLIPPERY_4,             -1, -1
8489   },
8490   {
8491     Xdecor_1,                           TRUE,   FALSE,
8492     EL_EMC_WALL_8,                      -1, -1
8493   },
8494   {
8495     Xdecor_2,                           TRUE,   FALSE,
8496     EL_EMC_WALL_6,                      -1, -1
8497   },
8498   {
8499     Xdecor_3,                           TRUE,   FALSE,
8500     EL_EMC_WALL_4,                      -1, -1
8501   },
8502   {
8503     Xdecor_4,                           TRUE,   FALSE,
8504     EL_EMC_WALL_7,                      -1, -1
8505   },
8506   {
8507     Xdecor_5,                           TRUE,   FALSE,
8508     EL_EMC_WALL_5,                      -1, -1
8509   },
8510   {
8511     Xdecor_6,                           TRUE,   FALSE,
8512     EL_EMC_WALL_9,                      -1, -1
8513   },
8514   {
8515     Xdecor_7,                           TRUE,   FALSE,
8516     EL_EMC_WALL_10,                     -1, -1
8517   },
8518   {
8519     Xdecor_8,                           TRUE,   FALSE,
8520     EL_EMC_WALL_1,                      -1, -1
8521   },
8522   {
8523     Xdecor_9,                           TRUE,   FALSE,
8524     EL_EMC_WALL_2,                      -1, -1
8525   },
8526   {
8527     Xdecor_10,                          TRUE,   FALSE,
8528     EL_EMC_WALL_3,                      -1, -1
8529   },
8530   {
8531     Xdecor_11,                          TRUE,   FALSE,
8532     EL_EMC_WALL_11,                     -1, -1
8533   },
8534   {
8535     Xdecor_12,                          TRUE,   FALSE,
8536     EL_EMC_WALL_12,                     -1, -1
8537   },
8538   {
8539     Xalpha_0,                           TRUE,   FALSE,
8540     EL_CHAR('0'),                       -1, -1
8541   },
8542   {
8543     Xalpha_1,                           TRUE,   FALSE,
8544     EL_CHAR('1'),                       -1, -1
8545   },
8546   {
8547     Xalpha_2,                           TRUE,   FALSE,
8548     EL_CHAR('2'),                       -1, -1
8549   },
8550   {
8551     Xalpha_3,                           TRUE,   FALSE,
8552     EL_CHAR('3'),                       -1, -1
8553   },
8554   {
8555     Xalpha_4,                           TRUE,   FALSE,
8556     EL_CHAR('4'),                       -1, -1
8557   },
8558   {
8559     Xalpha_5,                           TRUE,   FALSE,
8560     EL_CHAR('5'),                       -1, -1
8561   },
8562   {
8563     Xalpha_6,                           TRUE,   FALSE,
8564     EL_CHAR('6'),                       -1, -1
8565   },
8566   {
8567     Xalpha_7,                           TRUE,   FALSE,
8568     EL_CHAR('7'),                       -1, -1
8569   },
8570   {
8571     Xalpha_8,                           TRUE,   FALSE,
8572     EL_CHAR('8'),                       -1, -1
8573   },
8574   {
8575     Xalpha_9,                           TRUE,   FALSE,
8576     EL_CHAR('9'),                       -1, -1
8577   },
8578   {
8579     Xalpha_excla,                       TRUE,   FALSE,
8580     EL_CHAR('!'),                       -1, -1
8581   },
8582   {
8583     Xalpha_quote,                       TRUE,   FALSE,
8584     EL_CHAR('"'),                       -1, -1
8585   },
8586   {
8587     Xalpha_comma,                       TRUE,   FALSE,
8588     EL_CHAR(','),                       -1, -1
8589   },
8590   {
8591     Xalpha_minus,                       TRUE,   FALSE,
8592     EL_CHAR('-'),                       -1, -1
8593   },
8594   {
8595     Xalpha_perio,                       TRUE,   FALSE,
8596     EL_CHAR('.'),                       -1, -1
8597   },
8598   {
8599     Xalpha_colon,                       TRUE,   FALSE,
8600     EL_CHAR(':'),                       -1, -1
8601   },
8602   {
8603     Xalpha_quest,                       TRUE,   FALSE,
8604     EL_CHAR('?'),                       -1, -1
8605   },
8606   {
8607     Xalpha_a,                           TRUE,   FALSE,
8608     EL_CHAR('A'),                       -1, -1
8609   },
8610   {
8611     Xalpha_b,                           TRUE,   FALSE,
8612     EL_CHAR('B'),                       -1, -1
8613   },
8614   {
8615     Xalpha_c,                           TRUE,   FALSE,
8616     EL_CHAR('C'),                       -1, -1
8617   },
8618   {
8619     Xalpha_d,                           TRUE,   FALSE,
8620     EL_CHAR('D'),                       -1, -1
8621   },
8622   {
8623     Xalpha_e,                           TRUE,   FALSE,
8624     EL_CHAR('E'),                       -1, -1
8625   },
8626   {
8627     Xalpha_f,                           TRUE,   FALSE,
8628     EL_CHAR('F'),                       -1, -1
8629   },
8630   {
8631     Xalpha_g,                           TRUE,   FALSE,
8632     EL_CHAR('G'),                       -1, -1
8633   },
8634   {
8635     Xalpha_h,                           TRUE,   FALSE,
8636     EL_CHAR('H'),                       -1, -1
8637   },
8638   {
8639     Xalpha_i,                           TRUE,   FALSE,
8640     EL_CHAR('I'),                       -1, -1
8641   },
8642   {
8643     Xalpha_j,                           TRUE,   FALSE,
8644     EL_CHAR('J'),                       -1, -1
8645   },
8646   {
8647     Xalpha_k,                           TRUE,   FALSE,
8648     EL_CHAR('K'),                       -1, -1
8649   },
8650   {
8651     Xalpha_l,                           TRUE,   FALSE,
8652     EL_CHAR('L'),                       -1, -1
8653   },
8654   {
8655     Xalpha_m,                           TRUE,   FALSE,
8656     EL_CHAR('M'),                       -1, -1
8657   },
8658   {
8659     Xalpha_n,                           TRUE,   FALSE,
8660     EL_CHAR('N'),                       -1, -1
8661   },
8662   {
8663     Xalpha_o,                           TRUE,   FALSE,
8664     EL_CHAR('O'),                       -1, -1
8665   },
8666   {
8667     Xalpha_p,                           TRUE,   FALSE,
8668     EL_CHAR('P'),                       -1, -1
8669   },
8670   {
8671     Xalpha_q,                           TRUE,   FALSE,
8672     EL_CHAR('Q'),                       -1, -1
8673   },
8674   {
8675     Xalpha_r,                           TRUE,   FALSE,
8676     EL_CHAR('R'),                       -1, -1
8677   },
8678   {
8679     Xalpha_s,                           TRUE,   FALSE,
8680     EL_CHAR('S'),                       -1, -1
8681   },
8682   {
8683     Xalpha_t,                           TRUE,   FALSE,
8684     EL_CHAR('T'),                       -1, -1
8685   },
8686   {
8687     Xalpha_u,                           TRUE,   FALSE,
8688     EL_CHAR('U'),                       -1, -1
8689   },
8690   {
8691     Xalpha_v,                           TRUE,   FALSE,
8692     EL_CHAR('V'),                       -1, -1
8693   },
8694   {
8695     Xalpha_w,                           TRUE,   FALSE,
8696     EL_CHAR('W'),                       -1, -1
8697   },
8698   {
8699     Xalpha_x,                           TRUE,   FALSE,
8700     EL_CHAR('X'),                       -1, -1
8701   },
8702   {
8703     Xalpha_y,                           TRUE,   FALSE,
8704     EL_CHAR('Y'),                       -1, -1
8705   },
8706   {
8707     Xalpha_z,                           TRUE,   FALSE,
8708     EL_CHAR('Z'),                       -1, -1
8709   },
8710   {
8711     Xalpha_arrow_e,                     TRUE,   FALSE,
8712     EL_CHAR('>'),                       -1, -1
8713   },
8714   {
8715     Xalpha_arrow_w,                     TRUE,   FALSE,
8716     EL_CHAR('<'),                       -1, -1
8717   },
8718   {
8719     Xalpha_copyr,                       TRUE,   FALSE,
8720     EL_CHAR('©'),                       -1, -1
8721   },
8722
8723   {
8724     Xboom_bug,                          FALSE,  FALSE,
8725     EL_BUG,                             ACTION_EXPLODING, -1
8726   },
8727   {
8728     Xboom_bomb,                         FALSE,  FALSE,
8729     EL_BOMB,                            ACTION_EXPLODING, -1
8730   },
8731   {
8732     Xboom_android,                      FALSE,  FALSE,
8733     EL_EMC_ANDROID,                     ACTION_OTHER, -1
8734   },
8735   {
8736     Xboom_1,                            FALSE,  FALSE,
8737     EL_DEFAULT,                         ACTION_EXPLODING, -1
8738   },
8739   {
8740     Xboom_2,                            FALSE,  FALSE,
8741     EL_DEFAULT,                         ACTION_EXPLODING, -1
8742   },
8743   {
8744     Znormal,                            FALSE,  FALSE,
8745     EL_EMPTY,                           -1, -1
8746   },
8747   {
8748     Zdynamite,                          FALSE,  FALSE,
8749     EL_EMPTY,                           -1, -1
8750   },
8751   {
8752     Zplayer,                            FALSE,  FALSE,
8753     EL_EMPTY,                           -1, -1
8754   },
8755   {
8756     ZBORDER,                            FALSE,  FALSE,
8757     EL_EMPTY,                           -1, -1
8758   },
8759
8760   {
8761     -1,                                 FALSE,  FALSE,
8762     -1,                                 -1, -1
8763   }
8764 };
8765
8766 static struct Mapping_EM_to_RND_player
8767 {
8768   int action_em;
8769   int player_nr;
8770
8771   int element_rnd;
8772   int action;
8773   int direction;
8774 }
8775 em_player_mapping_list[] =
8776 {
8777   {
8778     SPR_walk + 0,                       0,
8779     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_UP,
8780   },
8781   {
8782     SPR_walk + 1,                       0,
8783     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_RIGHT,
8784   },
8785   {
8786     SPR_walk + 2,                       0,
8787     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_DOWN,
8788   },
8789   {
8790     SPR_walk + 3,                       0,
8791     EL_PLAYER_1,                        ACTION_MOVING, MV_BIT_LEFT,
8792   },
8793   {
8794     SPR_push + 0,                       0,
8795     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_UP,
8796   },
8797   {
8798     SPR_push + 1,                       0,
8799     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_RIGHT,
8800   },
8801   {
8802     SPR_push + 2,                       0,
8803     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_DOWN,
8804   },
8805   {
8806     SPR_push + 3,                       0,
8807     EL_PLAYER_1,                        ACTION_PUSHING, MV_BIT_LEFT,
8808   },
8809   {
8810     SPR_spray + 0,                      0,
8811     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_UP,
8812   },
8813   {
8814     SPR_spray + 1,                      0,
8815     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8816   },
8817   {
8818     SPR_spray + 2,                      0,
8819     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_DOWN,
8820   },
8821   {
8822     SPR_spray + 3,                      0,
8823     EL_PLAYER_1,                        ACTION_SNAPPING, MV_BIT_LEFT,
8824   },
8825   {
8826     SPR_walk + 0,                       1,
8827     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_UP,
8828   },
8829   {
8830     SPR_walk + 1,                       1,
8831     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_RIGHT,
8832   },
8833   {
8834     SPR_walk + 2,                       1,
8835     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_DOWN,
8836   },
8837   {
8838     SPR_walk + 3,                       1,
8839     EL_PLAYER_2,                        ACTION_MOVING, MV_BIT_LEFT,
8840   },
8841   {
8842     SPR_push + 0,                       1,
8843     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_UP,
8844   },
8845   {
8846     SPR_push + 1,                       1,
8847     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_RIGHT,
8848   },
8849   {
8850     SPR_push + 2,                       1,
8851     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_DOWN,
8852   },
8853   {
8854     SPR_push + 3,                       1,
8855     EL_PLAYER_2,                        ACTION_PUSHING, MV_BIT_LEFT,
8856   },
8857   {
8858     SPR_spray + 0,                      1,
8859     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_UP,
8860   },
8861   {
8862     SPR_spray + 1,                      1,
8863     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8864   },
8865   {
8866     SPR_spray + 2,                      1,
8867     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_DOWN,
8868   },
8869   {
8870     SPR_spray + 3,                      1,
8871     EL_PLAYER_2,                        ACTION_SNAPPING, MV_BIT_LEFT,
8872   },
8873   {
8874     SPR_still,                          0,
8875     EL_PLAYER_1,                        ACTION_DEFAULT, -1,
8876   },
8877   {
8878     SPR_still,                          1,
8879     EL_PLAYER_2,                        ACTION_DEFAULT, -1,
8880   },
8881   {
8882     SPR_walk + 0,                       2,
8883     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_UP,
8884   },
8885   {
8886     SPR_walk + 1,                       2,
8887     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_RIGHT,
8888   },
8889   {
8890     SPR_walk + 2,                       2,
8891     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_DOWN,
8892   },
8893   {
8894     SPR_walk + 3,                       2,
8895     EL_PLAYER_3,                        ACTION_MOVING, MV_BIT_LEFT,
8896   },
8897   {
8898     SPR_push + 0,                       2,
8899     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_UP,
8900   },
8901   {
8902     SPR_push + 1,                       2,
8903     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_RIGHT,
8904   },
8905   {
8906     SPR_push + 2,                       2,
8907     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_DOWN,
8908   },
8909   {
8910     SPR_push + 3,                       2,
8911     EL_PLAYER_3,                        ACTION_PUSHING, MV_BIT_LEFT,
8912   },
8913   {
8914     SPR_spray + 0,                      2,
8915     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_UP,
8916   },
8917   {
8918     SPR_spray + 1,                      2,
8919     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8920   },
8921   {
8922     SPR_spray + 2,                      2,
8923     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_DOWN,
8924   },
8925   {
8926     SPR_spray + 3,                      2,
8927     EL_PLAYER_3,                        ACTION_SNAPPING, MV_BIT_LEFT,
8928   },
8929   {
8930     SPR_walk + 0,                       3,
8931     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_UP,
8932   },
8933   {
8934     SPR_walk + 1,                       3,
8935     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_RIGHT,
8936   },
8937   {
8938     SPR_walk + 2,                       3,
8939     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_DOWN,
8940   },
8941   {
8942     SPR_walk + 3,                       3,
8943     EL_PLAYER_4,                        ACTION_MOVING, MV_BIT_LEFT,
8944   },
8945   {
8946     SPR_push + 0,                       3,
8947     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_UP,
8948   },
8949   {
8950     SPR_push + 1,                       3,
8951     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_RIGHT,
8952   },
8953   {
8954     SPR_push + 2,                       3,
8955     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_DOWN,
8956   },
8957   {
8958     SPR_push + 3,                       3,
8959     EL_PLAYER_4,                        ACTION_PUSHING, MV_BIT_LEFT,
8960   },
8961   {
8962     SPR_spray + 0,                      3,
8963     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_UP,
8964   },
8965   {
8966     SPR_spray + 1,                      3,
8967     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_RIGHT,
8968   },
8969   {
8970     SPR_spray + 2,                      3,
8971     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_DOWN,
8972   },
8973   {
8974     SPR_spray + 3,                      3,
8975     EL_PLAYER_4,                        ACTION_SNAPPING, MV_BIT_LEFT,
8976   },
8977   {
8978     SPR_still,                          2,
8979     EL_PLAYER_3,                        ACTION_DEFAULT, -1,
8980   },
8981   {
8982     SPR_still,                          3,
8983     EL_PLAYER_4,                        ACTION_DEFAULT, -1,
8984   },
8985
8986   {
8987     -1,                                 -1,
8988     -1,                                 -1, -1
8989   }
8990 };
8991
8992 int map_element_RND_to_EM(int element_rnd)
8993 {
8994   static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
8995   static boolean mapping_initialized = FALSE;
8996
8997   if (!mapping_initialized)
8998   {
8999     int i;
9000
9001     /* return "Xalpha_quest" for all undefined elements in mapping array */
9002     for (i = 0; i < NUM_FILE_ELEMENTS; i++)
9003       mapping_RND_to_EM[i] = Xalpha_quest;
9004
9005     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9006       if (em_object_mapping_list[i].is_rnd_to_em_mapping)
9007         mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
9008           em_object_mapping_list[i].element_em;
9009
9010     mapping_initialized = TRUE;
9011   }
9012
9013   if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
9014     return mapping_RND_to_EM[element_rnd];
9015
9016   Error(ERR_WARN, "invalid RND level element %d", element_rnd);
9017
9018   return EL_UNKNOWN;
9019 }
9020
9021 int map_element_EM_to_RND(int element_em)
9022 {
9023   static unsigned short mapping_EM_to_RND[TILE_MAX];
9024   static boolean mapping_initialized = FALSE;
9025
9026   if (!mapping_initialized)
9027   {
9028     int i;
9029
9030     /* return "EL_UNKNOWN" for all undefined elements in mapping array */
9031     for (i = 0; i < TILE_MAX; i++)
9032       mapping_EM_to_RND[i] = EL_UNKNOWN;
9033
9034     for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9035       mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
9036         em_object_mapping_list[i].element_rnd;
9037
9038     mapping_initialized = TRUE;
9039   }
9040
9041   if (element_em >= 0 && element_em < TILE_MAX)
9042     return mapping_EM_to_RND[element_em];
9043
9044   Error(ERR_WARN, "invalid EM level element %d", element_em);
9045
9046   return EL_UNKNOWN;
9047 }
9048
9049 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
9050 {
9051   struct LevelInfo_EM *level_em = level->native_em_level;
9052   struct LEVEL *lev = level_em->lev;
9053   int i, j;
9054
9055   for (i = 0; i < TILE_MAX; i++)
9056     lev->android_array[i] = Xblank;
9057
9058   for (i = 0; i < level->num_android_clone_elements; i++)
9059   {
9060     int element_rnd = level->android_clone_element[i];
9061     int element_em = map_element_RND_to_EM(element_rnd);
9062
9063     for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
9064       if (em_object_mapping_list[j].element_rnd == element_rnd)
9065         lev->android_array[em_object_mapping_list[j].element_em] = element_em;
9066   }
9067 }
9068
9069 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
9070 {
9071   struct LevelInfo_EM *level_em = level->native_em_level;
9072   struct LEVEL *lev = level_em->lev;
9073   int i, j;
9074
9075   level->num_android_clone_elements = 0;
9076
9077   for (i = 0; i < TILE_MAX; i++)
9078   {
9079     int element_em = lev->android_array[i];
9080     int element_rnd;
9081     boolean element_found = FALSE;
9082
9083     if (element_em == Xblank)
9084       continue;
9085
9086     element_rnd = map_element_EM_to_RND(element_em);
9087
9088     for (j = 0; j < level->num_android_clone_elements; j++)
9089       if (level->android_clone_element[j] == element_rnd)
9090         element_found = TRUE;
9091
9092     if (!element_found)
9093     {
9094       level->android_clone_element[level->num_android_clone_elements++] =
9095         element_rnd;
9096
9097       if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
9098         break;
9099     }
9100   }
9101
9102   if (level->num_android_clone_elements == 0)
9103   {
9104     level->num_android_clone_elements = 1;
9105     level->android_clone_element[0] = EL_EMPTY;
9106   }
9107 }
9108
9109 int map_direction_RND_to_EM(int direction)
9110 {
9111   return (direction == MV_UP    ? 0 :
9112           direction == MV_RIGHT ? 1 :
9113           direction == MV_DOWN  ? 2 :
9114           direction == MV_LEFT  ? 3 :
9115           -1);
9116 }
9117
9118 int map_direction_EM_to_RND(int direction)
9119 {
9120   return (direction == 0 ? MV_UP    :
9121           direction == 1 ? MV_RIGHT :
9122           direction == 2 ? MV_DOWN  :
9123           direction == 3 ? MV_LEFT  :
9124           MV_NONE);
9125 }
9126
9127 int map_element_RND_to_SP(int element_rnd)
9128 {
9129   int element_sp = 0x20;        /* map unknown elements to yellow "hardware" */
9130
9131   if (element_rnd >= EL_SP_START &&
9132       element_rnd <= EL_SP_END)
9133     element_sp = element_rnd - EL_SP_START;
9134   else if (element_rnd == EL_EMPTY_SPACE)
9135     element_sp = 0x00;
9136   else if (element_rnd == EL_INVISIBLE_WALL)
9137     element_sp = 0x28;
9138
9139   return element_sp;
9140 }
9141
9142 int map_element_SP_to_RND(int element_sp)
9143 {
9144   int element_rnd = EL_UNKNOWN;
9145
9146   if (element_sp >= 0x00 &&
9147       element_sp <= 0x27)
9148     element_rnd = EL_SP_START + element_sp;
9149   else if (element_sp == 0x28)
9150     element_rnd = EL_INVISIBLE_WALL;
9151
9152   return element_rnd;
9153 }
9154
9155 int map_action_SP_to_RND(int action_sp)
9156 {
9157   switch (action_sp)
9158   {
9159     case actActive:             return ACTION_ACTIVE;
9160     case actImpact:             return ACTION_IMPACT;
9161     case actExploding:          return ACTION_EXPLODING;
9162     case actDigging:            return ACTION_DIGGING;
9163     case actSnapping:           return ACTION_SNAPPING;
9164     case actCollecting:         return ACTION_COLLECTING;
9165     case actPassing:            return ACTION_PASSING;
9166     case actPushing:            return ACTION_PUSHING;
9167     case actDropping:           return ACTION_DROPPING;
9168
9169     default:                    return ACTION_DEFAULT;
9170   }
9171 }
9172
9173 int get_next_element(int element)
9174 {
9175   switch (element)
9176   {
9177     case EL_QUICKSAND_FILLING:          return EL_QUICKSAND_FULL;
9178     case EL_QUICKSAND_EMPTYING:         return EL_QUICKSAND_EMPTY;
9179     case EL_QUICKSAND_FAST_FILLING:     return EL_QUICKSAND_FAST_FULL;
9180     case EL_QUICKSAND_FAST_EMPTYING:    return EL_QUICKSAND_FAST_EMPTY;
9181     case EL_MAGIC_WALL_FILLING:         return EL_MAGIC_WALL_FULL;
9182     case EL_MAGIC_WALL_EMPTYING:        return EL_MAGIC_WALL_ACTIVE;
9183     case EL_BD_MAGIC_WALL_FILLING:      return EL_BD_MAGIC_WALL_FULL;
9184     case EL_BD_MAGIC_WALL_EMPTYING:     return EL_BD_MAGIC_WALL_ACTIVE;
9185     case EL_DC_MAGIC_WALL_FILLING:      return EL_DC_MAGIC_WALL_FULL;
9186     case EL_DC_MAGIC_WALL_EMPTYING:     return EL_DC_MAGIC_WALL_ACTIVE;
9187     case EL_AMOEBA_DROPPING:            return EL_AMOEBA_WET;
9188
9189     default:                            return element;
9190   }
9191 }
9192
9193 #if 0
9194 int el_act_dir2img(int element, int action, int direction)
9195 {
9196   element = GFX_ELEMENT(element);
9197
9198   if (direction == MV_NONE)
9199     return element_info[element].graphic[action];
9200
9201   direction = MV_DIR_TO_BIT(direction);
9202
9203   return element_info[element].direction_graphic[action][direction];
9204 }
9205 #else
9206 int el_act_dir2img(int element, int action, int direction)
9207 {
9208   element = GFX_ELEMENT(element);
9209   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9210
9211   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9212   return element_info[element].direction_graphic[action][direction];
9213 }
9214 #endif
9215
9216 #if 0
9217 static int el_act_dir2crm(int element, int action, int direction)
9218 {
9219   element = GFX_ELEMENT(element);
9220
9221   if (direction == MV_NONE)
9222     return element_info[element].crumbled[action];
9223
9224   direction = MV_DIR_TO_BIT(direction);
9225
9226   return element_info[element].direction_crumbled[action][direction];
9227 }
9228 #else
9229 static int el_act_dir2crm(int element, int action, int direction)
9230 {
9231   element = GFX_ELEMENT(element);
9232   direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
9233
9234   /* direction_graphic[][] == graphic[] for undefined direction graphics */
9235   return element_info[element].direction_crumbled[action][direction];
9236 }
9237 #endif
9238
9239 int el_act2img(int element, int action)
9240 {
9241   element = GFX_ELEMENT(element);
9242
9243   return element_info[element].graphic[action];
9244 }
9245
9246 int el_act2crm(int element, int action)
9247 {
9248   element = GFX_ELEMENT(element);
9249
9250   return element_info[element].crumbled[action];
9251 }
9252
9253 int el_dir2img(int element, int direction)
9254 {
9255   element = GFX_ELEMENT(element);
9256
9257   return el_act_dir2img(element, ACTION_DEFAULT, direction);
9258 }
9259
9260 int el2baseimg(int element)
9261 {
9262   return element_info[element].graphic[ACTION_DEFAULT];
9263 }
9264
9265 int el2img(int element)
9266 {
9267   element = GFX_ELEMENT(element);
9268
9269   return element_info[element].graphic[ACTION_DEFAULT];
9270 }
9271
9272 int el2edimg(int element)
9273 {
9274   element = GFX_ELEMENT(element);
9275
9276   return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
9277 }
9278
9279 int el2preimg(int element)
9280 {
9281   element = GFX_ELEMENT(element);
9282
9283   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
9284 }
9285
9286 int el2panelimg(int element)
9287 {
9288   element = GFX_ELEMENT(element);
9289
9290   return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
9291 }
9292
9293 int font2baseimg(int font_nr)
9294 {
9295   return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
9296 }
9297
9298 int getBeltNrFromBeltElement(int element)
9299 {
9300   return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
9301           element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
9302           element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
9303 }
9304
9305 int getBeltNrFromBeltActiveElement(int element)
9306 {
9307   return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
9308           element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
9309           element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
9310 }
9311
9312 int getBeltNrFromBeltSwitchElement(int element)
9313 {
9314   return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
9315           element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
9316           element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
9317 }
9318
9319 int getBeltDirNrFromBeltElement(int element)
9320 {
9321   static int belt_base_element[4] =
9322   {
9323     EL_CONVEYOR_BELT_1_LEFT,
9324     EL_CONVEYOR_BELT_2_LEFT,
9325     EL_CONVEYOR_BELT_3_LEFT,
9326     EL_CONVEYOR_BELT_4_LEFT
9327   };
9328
9329   int belt_nr = getBeltNrFromBeltElement(element);
9330   int belt_dir_nr = element - belt_base_element[belt_nr];
9331
9332   return (belt_dir_nr % 3);
9333 }
9334
9335 int getBeltDirNrFromBeltSwitchElement(int element)
9336 {
9337   static int belt_base_element[4] =
9338   {
9339     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9340     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9341     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9342     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9343   };
9344
9345   int belt_nr = getBeltNrFromBeltSwitchElement(element);
9346   int belt_dir_nr = element - belt_base_element[belt_nr];
9347
9348   return (belt_dir_nr % 3);
9349 }
9350
9351 int getBeltDirFromBeltElement(int element)
9352 {
9353   static int belt_move_dir[3] =
9354   {
9355     MV_LEFT,
9356     MV_NONE,
9357     MV_RIGHT
9358   };
9359
9360   int belt_dir_nr = getBeltDirNrFromBeltElement(element);
9361
9362   return belt_move_dir[belt_dir_nr];
9363 }
9364
9365 int getBeltDirFromBeltSwitchElement(int element)
9366 {
9367   static int belt_move_dir[3] =
9368   {
9369     MV_LEFT,
9370     MV_NONE,
9371     MV_RIGHT
9372   };
9373
9374   int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
9375
9376   return belt_move_dir[belt_dir_nr];
9377 }
9378
9379 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9380 {
9381   static int belt_base_element[4] =
9382   {
9383     EL_CONVEYOR_BELT_1_LEFT,
9384     EL_CONVEYOR_BELT_2_LEFT,
9385     EL_CONVEYOR_BELT_3_LEFT,
9386     EL_CONVEYOR_BELT_4_LEFT
9387   };
9388
9389   return belt_base_element[belt_nr] + belt_dir_nr;
9390 }
9391
9392 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9393 {
9394   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9395
9396   return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9397 }
9398
9399 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
9400 {
9401   static int belt_base_element[4] =
9402   {
9403     EL_CONVEYOR_BELT_1_SWITCH_LEFT,
9404     EL_CONVEYOR_BELT_2_SWITCH_LEFT,
9405     EL_CONVEYOR_BELT_3_SWITCH_LEFT,
9406     EL_CONVEYOR_BELT_4_SWITCH_LEFT
9407   };
9408
9409   return belt_base_element[belt_nr] + belt_dir_nr;
9410 }
9411
9412 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
9413 {
9414   int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
9415
9416   return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
9417 }
9418
9419 #if 1
9420 boolean getTeamMode_EM()
9421 {
9422   return game.team_mode;
9423 }
9424 #else
9425 int getNumActivePlayers_EM()
9426 {
9427 #if 1
9428   int num_players = 0;
9429   int i;
9430
9431   if (!tape.playing)
9432     return (setup.team_mode ? MAX_PLAYERS : 1);
9433
9434   for (i = 0; i < MAX_PLAYERS; i++)
9435     if (tape.player_participates[i])
9436       num_players++;
9437
9438   return (num_players > 1 ? MAX_PLAYERS : 1);
9439
9440 #else
9441
9442   int num_players = 0;
9443   int i;
9444
9445   /* when recording game, activate all connected players */
9446   if (!tape.playing)
9447     return -1;
9448
9449   for (i = 0; i < MAX_PLAYERS; i++)
9450     if (tape.player_participates[i])
9451       num_players++;
9452
9453   return num_players;
9454 #endif
9455 }
9456 #endif
9457
9458 int getGameFrameDelay_EM(int native_em_game_frame_delay)
9459 {
9460   int game_frame_delay_value;
9461
9462   game_frame_delay_value =
9463     (tape.playing && tape.fast_forward ? FfwdFrameDelay :
9464      GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
9465      GameFrameDelay);
9466
9467   if (tape.playing && tape.warp_forward && !tape.pausing)
9468     game_frame_delay_value = 0;
9469
9470   return game_frame_delay_value;
9471 }
9472
9473 unsigned int InitRND(int seed)
9474 {
9475   if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
9476     return InitEngineRandom_EM(seed);
9477   else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
9478     return InitEngineRandom_SP(seed);
9479   else
9480     return InitEngineRandom_RND(seed);
9481 }
9482
9483 #if 1
9484 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9485 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9486 #endif
9487
9488 inline static int get_effective_element_EM(int tile, int frame_em)
9489 {
9490   int element             = object_mapping[tile].element_rnd;
9491   int action              = object_mapping[tile].action;
9492   boolean is_backside     = object_mapping[tile].is_backside;
9493   boolean action_removing = (action == ACTION_DIGGING ||
9494                              action == ACTION_SNAPPING ||
9495                              action == ACTION_COLLECTING);
9496
9497   if (frame_em < 7)
9498   {
9499     switch (tile)
9500     {
9501       case Yacid_splash_eB:
9502       case Yacid_splash_wB:
9503         return (frame_em > 5 ? EL_EMPTY : element);
9504
9505 #if 0
9506         /* !!! FIX !!! */
9507       case Ydiamond_stone:
9508         //  if (!game.use_native_emc_graphics_engine)
9509         return EL_ROCK;
9510 #endif
9511
9512       default:
9513         return element;
9514     }
9515   }
9516   else  /* frame_em == 7 */
9517   {
9518     switch (tile)
9519     {
9520       case Yacid_splash_eB:
9521       case Yacid_splash_wB:
9522         return EL_EMPTY;
9523
9524       case Yemerald_stone:
9525         return EL_EMERALD;
9526
9527       case Ydiamond_stone:
9528         return EL_ROCK;
9529
9530       case Xdrip_stretch:
9531       case Xdrip_stretchB:
9532       case Ydrip_s1:
9533       case Ydrip_s1B:
9534       case Xball_1B:
9535       case Xball_2:
9536       case Xball_2B:
9537       case Yball_eat:
9538       case Ykey_1_eat:
9539       case Ykey_2_eat:
9540       case Ykey_3_eat:
9541       case Ykey_4_eat:
9542       case Ykey_5_eat:
9543       case Ykey_6_eat:
9544       case Ykey_7_eat:
9545       case Ykey_8_eat:
9546       case Ylenses_eat:
9547       case Ymagnify_eat:
9548       case Ygrass_eat:
9549       case Ydirt_eat:
9550       case Xsand_stonein_1:
9551       case Xsand_stonein_2:
9552       case Xsand_stonein_3:
9553       case Xsand_stonein_4:
9554         return element;
9555
9556       default:
9557         return (is_backside || action_removing ? EL_EMPTY : element);
9558     }
9559   }
9560 }
9561
9562 inline static boolean check_linear_animation_EM(int tile)
9563 {
9564   switch (tile)
9565   {
9566     case Xsand_stonesand_1:
9567     case Xsand_stonesand_quickout_1:
9568     case Xsand_sandstone_1:
9569     case Xsand_stonein_1:
9570     case Xsand_stoneout_1:
9571     case Xboom_1:
9572     case Xdynamite_1:
9573     case Ybug_w_n:
9574     case Ybug_n_e:
9575     case Ybug_e_s:
9576     case Ybug_s_w:
9577     case Ybug_e_n:
9578     case Ybug_s_e:
9579     case Ybug_w_s:
9580     case Ybug_n_w:
9581     case Ytank_w_n:
9582     case Ytank_n_e:
9583     case Ytank_e_s:
9584     case Ytank_s_w:
9585     case Ytank_e_n:
9586     case Ytank_s_e:
9587     case Ytank_w_s:
9588     case Ytank_n_w:
9589 #if 1
9590     case Yacid_splash_eB:
9591     case Yacid_splash_wB:
9592     case Yemerald_stone:
9593 #endif
9594       return TRUE;
9595   }
9596
9597   return FALSE;
9598 }
9599
9600 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
9601                                             boolean has_crumbled_graphics,
9602                                             int crumbled, int sync_frame)
9603 {
9604   /* if element can be crumbled, but certain action graphics are just empty
9605      space (like instantly snapping sand to empty space in 1 frame), do not
9606      treat these empty space graphics as crumbled graphics in EMC engine */
9607   if (crumbled == IMG_EMPTY_SPACE)
9608     has_crumbled_graphics = FALSE;
9609
9610   if (has_crumbled_graphics)
9611   {
9612     struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9613     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9614                                            g_crumbled->anim_delay,
9615                                            g_crumbled->anim_mode,
9616                                            g_crumbled->anim_start_frame,
9617                                            sync_frame);
9618
9619     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
9620                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
9621
9622     g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9623
9624     g_em->has_crumbled_graphics = TRUE;
9625   }
9626   else
9627   {
9628     g_em->crumbled_bitmap = NULL;
9629     g_em->crumbled_src_x = 0;
9630     g_em->crumbled_src_y = 0;
9631     g_em->crumbled_border_size = 0;
9632
9633     g_em->has_crumbled_graphics = FALSE;
9634   }
9635 }
9636
9637 void ResetGfxAnimation_EM(int x, int y, int tile)
9638 {
9639   GfxFrame[x][y] = 0;
9640 }
9641
9642 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
9643                         int tile, int frame_em, int x, int y)
9644 {
9645   int action = object_mapping[tile].action;
9646 #if 1
9647   int direction = object_mapping[tile].direction;
9648   int effective_element = get_effective_element_EM(tile, frame_em);
9649   int graphic = (direction == MV_NONE ?
9650                  el_act2img(effective_element, action) :
9651                  el_act_dir2img(effective_element, action, direction));
9652   struct GraphicInfo *g = &graphic_info[graphic];
9653   int sync_frame;
9654 #endif
9655   boolean action_removing = (action == ACTION_DIGGING ||
9656                              action == ACTION_SNAPPING ||
9657                              action == ACTION_COLLECTING);
9658   boolean action_moving   = (action == ACTION_FALLING ||
9659                              action == ACTION_MOVING ||
9660                              action == ACTION_PUSHING ||
9661                              action == ACTION_EATING ||
9662                              action == ACTION_FILLING ||
9663                              action == ACTION_EMPTYING);
9664   boolean action_falling  = (action == ACTION_FALLING ||
9665                              action == ACTION_FILLING ||
9666                              action == ACTION_EMPTYING);
9667
9668   /* special case: graphic uses "2nd movement tile" and has defined
9669      7 frames for movement animation (or less) => use default graphic
9670      for last (8th) frame which ends the movement animation */
9671   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9672   {
9673     action = ACTION_DEFAULT;    /* (keep action_* unchanged for now) */
9674     graphic = (direction == MV_NONE ?
9675                el_act2img(effective_element, action) :
9676                el_act_dir2img(effective_element, action, direction));
9677
9678     g = &graphic_info[graphic];
9679   }
9680
9681 #if 0
9682   if (tile == Xsand_stonesand_1 ||
9683       tile == Xsand_stonesand_2 ||
9684       tile == Xsand_stonesand_3 ||
9685       tile == Xsand_stonesand_4)
9686     printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9687 #endif
9688
9689 #if 1
9690   if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
9691   {
9692     GfxFrame[x][y] = 0;
9693
9694     // printf("::: resetting... [%d]\n", tile);
9695   }
9696 #else
9697   if (action_removing || check_linear_animation_EM(tile))
9698   {
9699     GfxFrame[x][y] = frame_em;
9700
9701     // printf("::: resetting... [%d]\n", tile);
9702   }
9703 #endif
9704   else if (action_moving)
9705   {
9706     boolean is_backside = object_mapping[tile].is_backside;
9707
9708     if (is_backside)
9709     {
9710       int direction = object_mapping[tile].direction;
9711       int move_dir = (action_falling ? MV_DOWN : direction);
9712
9713       GfxFrame[x][y]++;
9714
9715 #if 1
9716       /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
9717       if (g->double_movement && frame_em == 0)
9718       {
9719         GfxFrame[x][y] = 0;
9720
9721         // printf("::: resetting... [%d]\n", tile);
9722       }
9723 #endif
9724
9725       if (move_dir == MV_LEFT)
9726         GfxFrame[x - 1][y] = GfxFrame[x][y];
9727       else if (move_dir == MV_RIGHT)
9728         GfxFrame[x + 1][y] = GfxFrame[x][y];
9729       else if (move_dir == MV_UP)
9730         GfxFrame[x][y - 1] = GfxFrame[x][y];
9731       else if (move_dir == MV_DOWN)
9732         GfxFrame[x][y + 1] = GfxFrame[x][y];
9733     }
9734   }
9735   else
9736   {
9737     GfxFrame[x][y]++;
9738
9739     /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
9740     if (tile == Xsand_stonesand_quickout_1 ||
9741         tile == Xsand_stonesand_quickout_2)
9742       GfxFrame[x][y]++;
9743   }
9744
9745 #if 0
9746   if (tile == Xsand_stonesand_1 ||
9747       tile == Xsand_stonesand_2 ||
9748       tile == Xsand_stonesand_3 ||
9749       tile == Xsand_stonesand_4)
9750     printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
9751 #endif
9752
9753 #if 1
9754   if (graphic_info[graphic].anim_global_sync)
9755     sync_frame = FrameCounter;
9756   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9757     sync_frame = GfxFrame[x][y];
9758   else
9759     sync_frame = 0;     /* playfield border (pseudo steel) */
9760
9761   SetRandomAnimationValue(x, y);
9762
9763   int frame = getAnimationFrame(g->anim_frames,
9764                                 g->anim_delay,
9765                                 g->anim_mode,
9766                                 g->anim_start_frame,
9767                                 sync_frame);
9768
9769   g_em->unique_identifier =
9770     (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
9771 #endif
9772 }
9773
9774 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
9775                                   int tile, int frame_em, int x, int y)
9776 {
9777   int action = object_mapping[tile].action;
9778   int direction = object_mapping[tile].direction;
9779   boolean is_backside = object_mapping[tile].is_backside;
9780   int effective_element = get_effective_element_EM(tile, frame_em);
9781 #if 1
9782   int effective_action = action;
9783 #else
9784   int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
9785 #endif
9786   int graphic = (direction == MV_NONE ?
9787                  el_act2img(effective_element, effective_action) :
9788                  el_act_dir2img(effective_element, effective_action,
9789                                 direction));
9790   int crumbled = (direction == MV_NONE ?
9791                   el_act2crm(effective_element, effective_action) :
9792                   el_act_dir2crm(effective_element, effective_action,
9793                                  direction));
9794   int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9795   int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9796   boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9797   struct GraphicInfo *g = &graphic_info[graphic];
9798 #if 0
9799   struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9800 #endif
9801   int sync_frame;
9802
9803   /* special case: graphic uses "2nd movement tile" and has defined
9804      7 frames for movement animation (or less) => use default graphic
9805      for last (8th) frame which ends the movement animation */
9806   if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
9807   {
9808     effective_action = ACTION_DEFAULT;
9809     graphic = (direction == MV_NONE ?
9810                el_act2img(effective_element, effective_action) :
9811                el_act_dir2img(effective_element, effective_action,
9812                               direction));
9813     crumbled = (direction == MV_NONE ?
9814                 el_act2crm(effective_element, effective_action) :
9815                 el_act_dir2crm(effective_element, effective_action,
9816                                direction));
9817
9818     g = &graphic_info[graphic];
9819   }
9820
9821 #if 0
9822   if (frame_em == 7)
9823     return;
9824 #endif
9825
9826
9827 #if 0
9828   if (frame_em == 0)    /* reset animation frame for certain elements */
9829   {
9830     if (check_linear_animation_EM(tile))
9831       GfxFrame[x][y] = 0;
9832   }
9833 #endif
9834
9835   if (graphic_info[graphic].anim_global_sync)
9836     sync_frame = FrameCounter;
9837   else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
9838     sync_frame = GfxFrame[x][y];
9839   else
9840     sync_frame = 0;     /* playfield border (pseudo steel) */
9841
9842   SetRandomAnimationValue(x, y);
9843
9844 #if 0
9845   int i = tile;
9846   int j = frame_em;
9847   int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
9848                         i == Xdrip_stretchB ? 7 :
9849                         i == Ydrip_s2 ? j + 8 :
9850                         i == Ydrip_s2B ? j + 8 :
9851                         i == Xacid_1 ? 0 :
9852                         i == Xacid_2 ? 10 :
9853                         i == Xacid_3 ? 20 :
9854                         i == Xacid_4 ? 30 :
9855                         i == Xacid_5 ? 40 :
9856                         i == Xacid_6 ? 50 :
9857                         i == Xacid_7 ? 60 :
9858                         i == Xacid_8 ? 70 :
9859                         i == Xfake_acid_1 ? 0 :
9860                         i == Xfake_acid_2 ? 10 :
9861                         i == Xfake_acid_3 ? 20 :
9862                         i == Xfake_acid_4 ? 30 :
9863                         i == Xfake_acid_5 ? 40 :
9864                         i == Xfake_acid_6 ? 50 :
9865                         i == Xfake_acid_7 ? 60 :
9866                         i == Xfake_acid_8 ? 70 :
9867                         i == Xball_2 ? 7 :
9868                         i == Xball_2B ? j + 8 :
9869                         i == Yball_eat ? j + 1 :
9870                         i == Ykey_1_eat ? j + 1 :
9871                         i == Ykey_2_eat ? j + 1 :
9872                         i == Ykey_3_eat ? j + 1 :
9873                         i == Ykey_4_eat ? j + 1 :
9874                         i == Ykey_5_eat ? j + 1 :
9875                         i == Ykey_6_eat ? j + 1 :
9876                         i == Ykey_7_eat ? j + 1 :
9877                         i == Ykey_8_eat ? j + 1 :
9878                         i == Ylenses_eat ? j + 1 :
9879                         i == Ymagnify_eat ? j + 1 :
9880                         i == Ygrass_eat ? j + 1 :
9881                         i == Ydirt_eat ? j + 1 :
9882                         i == Xamoeba_1 ? 0 :
9883                         i == Xamoeba_2 ? 1 :
9884                         i == Xamoeba_3 ? 2 :
9885                         i == Xamoeba_4 ? 3 :
9886                         i == Xamoeba_5 ? 0 :
9887                         i == Xamoeba_6 ? 1 :
9888                         i == Xamoeba_7 ? 2 :
9889                         i == Xamoeba_8 ? 3 :
9890                         i == Xexit_2 ? j + 8 :
9891                         i == Xexit_3 ? j + 16 :
9892                         i == Xdynamite_1 ? 0 :
9893                         i == Xdynamite_2 ? 8 :
9894                         i == Xdynamite_3 ? 16 :
9895                         i == Xdynamite_4 ? 24 :
9896                         i == Xsand_stonein_1 ? j + 1 :
9897                         i == Xsand_stonein_2 ? j + 9 :
9898                         i == Xsand_stonein_3 ? j + 17 :
9899                         i == Xsand_stonein_4 ? j + 25 :
9900                         i == Xsand_stoneout_1 && j == 0 ? 0 :
9901                         i == Xsand_stoneout_1 && j == 1 ? 0 :
9902                         i == Xsand_stoneout_1 && j == 2 ? 1 :
9903                         i == Xsand_stoneout_1 && j == 3 ? 2 :
9904                         i == Xsand_stoneout_1 && j == 4 ? 2 :
9905                         i == Xsand_stoneout_1 && j == 5 ? 3 :
9906                         i == Xsand_stoneout_1 && j == 6 ? 4 :
9907                         i == Xsand_stoneout_1 && j == 7 ? 4 :
9908                         i == Xsand_stoneout_2 && j == 0 ? 5 :
9909                         i == Xsand_stoneout_2 && j == 1 ? 6 :
9910                         i == Xsand_stoneout_2 && j == 2 ? 7 :
9911                         i == Xsand_stoneout_2 && j == 3 ? 8 :
9912                         i == Xsand_stoneout_2 && j == 4 ? 9 :
9913                         i == Xsand_stoneout_2 && j == 5 ? 11 :
9914                         i == Xsand_stoneout_2 && j == 6 ? 13 :
9915                         i == Xsand_stoneout_2 && j == 7 ? 15 :
9916                         i == Xboom_bug && j == 1 ? 2 :
9917                         i == Xboom_bug && j == 2 ? 2 :
9918                         i == Xboom_bug && j == 3 ? 4 :
9919                         i == Xboom_bug && j == 4 ? 4 :
9920                         i == Xboom_bug && j == 5 ? 2 :
9921                         i == Xboom_bug && j == 6 ? 2 :
9922                         i == Xboom_bug && j == 7 ? 0 :
9923                         i == Xboom_bomb && j == 1 ? 2 :
9924                         i == Xboom_bomb && j == 2 ? 2 :
9925                         i == Xboom_bomb && j == 3 ? 4 :
9926                         i == Xboom_bomb && j == 4 ? 4 :
9927                         i == Xboom_bomb && j == 5 ? 2 :
9928                         i == Xboom_bomb && j == 6 ? 2 :
9929                         i == Xboom_bomb && j == 7 ? 0 :
9930                         i == Xboom_android && j == 7 ? 6 :
9931                         i == Xboom_1 && j == 1 ? 2 :
9932                         i == Xboom_1 && j == 2 ? 2 :
9933                         i == Xboom_1 && j == 3 ? 4 :
9934                         i == Xboom_1 && j == 4 ? 4 :
9935                         i == Xboom_1 && j == 5 ? 6 :
9936                         i == Xboom_1 && j == 6 ? 6 :
9937                         i == Xboom_1 && j == 7 ? 8 :
9938                         i == Xboom_2 && j == 0 ? 8 :
9939                         i == Xboom_2 && j == 1 ? 8 :
9940                         i == Xboom_2 && j == 2 ? 10 :
9941                         i == Xboom_2 && j == 3 ? 10 :
9942                         i == Xboom_2 && j == 4 ? 10 :
9943                         i == Xboom_2 && j == 5 ? 12 :
9944                         i == Xboom_2 && j == 6 ? 12 :
9945                         i == Xboom_2 && j == 7 ? 12 :
9946 #if 0
9947                         special_animation && j == 4 ? 3 :
9948                         effective_action != action ? 0 :
9949 #endif
9950                         j);
9951 #endif
9952
9953 #if 0
9954   int xxx_effective_action;
9955   int xxx_has_action_graphics;
9956
9957   {
9958     int element = object_mapping[i].element_rnd;
9959     int action = object_mapping[i].action;
9960     int direction = object_mapping[i].direction;
9961     boolean is_backside = object_mapping[i].is_backside;
9962 #if 0
9963     boolean action_removing = (action == ACTION_DIGGING ||
9964                                action == ACTION_SNAPPING ||
9965                                action == ACTION_COLLECTING);
9966 #endif
9967     boolean action_exploding = ((action == ACTION_EXPLODING ||
9968                                  action == ACTION_SMASHED_BY_ROCK ||
9969                                  action == ACTION_SMASHED_BY_SPRING) &&
9970                                 element != EL_DIAMOND);
9971     boolean action_active = (action == ACTION_ACTIVE);
9972     boolean action_other = (action == ACTION_OTHER);
9973
9974     {
9975 #if 1
9976       int effective_element = get_effective_element_EM(i, j);
9977 #else
9978       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9979                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9980                                j < 7 ? element :
9981                                i == Xdrip_stretch ? element :
9982                                i == Xdrip_stretchB ? element :
9983                                i == Ydrip_s1 ? element :
9984                                i == Ydrip_s1B ? element :
9985                                i == Xball_1B ? element :
9986                                i == Xball_2 ? element :
9987                                i == Xball_2B ? element :
9988                                i == Yball_eat ? element :
9989                                i == Ykey_1_eat ? element :
9990                                i == Ykey_2_eat ? element :
9991                                i == Ykey_3_eat ? element :
9992                                i == Ykey_4_eat ? element :
9993                                i == Ykey_5_eat ? element :
9994                                i == Ykey_6_eat ? element :
9995                                i == Ykey_7_eat ? element :
9996                                i == Ykey_8_eat ? element :
9997                                i == Ylenses_eat ? element :
9998                                i == Ymagnify_eat ? element :
9999                                i == Ygrass_eat ? element :
10000                                i == Ydirt_eat ? element :
10001                                i == Yemerald_stone ? EL_EMERALD :
10002                                i == Ydiamond_stone ? EL_ROCK :
10003                                i == Xsand_stonein_1 ? element :
10004                                i == Xsand_stonein_2 ? element :
10005                                i == Xsand_stonein_3 ? element :
10006                                i == Xsand_stonein_4 ? element :
10007                                is_backside ? EL_EMPTY :
10008                                action_removing ? EL_EMPTY :
10009                                element);
10010 #endif
10011       int effective_action = (j < 7 ? action :
10012                               i == Xdrip_stretch ? action :
10013                               i == Xdrip_stretchB ? action :
10014                               i == Ydrip_s1 ? action :
10015                               i == Ydrip_s1B ? action :
10016                               i == Xball_1B ? action :
10017                               i == Xball_2 ? action :
10018                               i == Xball_2B ? action :
10019                               i == Yball_eat ? action :
10020                               i == Ykey_1_eat ? action :
10021                               i == Ykey_2_eat ? action :
10022                               i == Ykey_3_eat ? action :
10023                               i == Ykey_4_eat ? action :
10024                               i == Ykey_5_eat ? action :
10025                               i == Ykey_6_eat ? action :
10026                               i == Ykey_7_eat ? action :
10027                               i == Ykey_8_eat ? action :
10028                               i == Ylenses_eat ? action :
10029                               i == Ymagnify_eat ? action :
10030                               i == Ygrass_eat ? action :
10031                               i == Ydirt_eat ? action :
10032                               i == Xsand_stonein_1 ? action :
10033                               i == Xsand_stonein_2 ? action :
10034                               i == Xsand_stonein_3 ? action :
10035                               i == Xsand_stonein_4 ? action :
10036                               i == Xsand_stoneout_1 ? action :
10037                               i == Xsand_stoneout_2 ? action :
10038                               i == Xboom_android ? ACTION_EXPLODING :
10039                               action_exploding ? ACTION_EXPLODING :
10040                               action_active ? action :
10041                               action_other ? action :
10042                               ACTION_DEFAULT);
10043       int graphic = (el_act_dir2img(effective_element, effective_action,
10044                                     direction));
10045       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10046                                      direction));
10047       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10048       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10049       boolean has_action_graphics = (graphic != base_graphic);
10050       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10051       struct GraphicInfo *g = &graphic_info[graphic];
10052 #if 0
10053       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10054 #endif
10055       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10056       Bitmap *src_bitmap;
10057       int src_x, src_y;
10058       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10059       boolean special_animation = (action != ACTION_DEFAULT &&
10060                                    g->anim_frames == 3 &&
10061                                    g->anim_delay == 2 &&
10062                                    g->anim_mode & ANIM_LINEAR);
10063       xxx_sync_frame = (i == Xdrip_stretch ? 7 :
10064                         i == Xdrip_stretchB ? 7 :
10065                         i == Ydrip_s2 ? j + 8 :
10066                         i == Ydrip_s2B ? j + 8 :
10067                         i == Xacid_1 ? 0 :
10068                         i == Xacid_2 ? 10 :
10069                         i == Xacid_3 ? 20 :
10070                         i == Xacid_4 ? 30 :
10071                         i == Xacid_5 ? 40 :
10072                         i == Xacid_6 ? 50 :
10073                         i == Xacid_7 ? 60 :
10074                         i == Xacid_8 ? 70 :
10075                         i == Xfake_acid_1 ? 0 :
10076                         i == Xfake_acid_2 ? 10 :
10077                         i == Xfake_acid_3 ? 20 :
10078                         i == Xfake_acid_4 ? 30 :
10079                         i == Xfake_acid_5 ? 40 :
10080                         i == Xfake_acid_6 ? 50 :
10081                         i == Xfake_acid_7 ? 60 :
10082                         i == Xfake_acid_8 ? 70 :
10083                         i == Xball_2 ? 7 :
10084                         i == Xball_2B ? j + 8 :
10085                         i == Yball_eat ? j + 1 :
10086                         i == Ykey_1_eat ? j + 1 :
10087                         i == Ykey_2_eat ? j + 1 :
10088                         i == Ykey_3_eat ? j + 1 :
10089                         i == Ykey_4_eat ? j + 1 :
10090                         i == Ykey_5_eat ? j + 1 :
10091                         i == Ykey_6_eat ? j + 1 :
10092                         i == Ykey_7_eat ? j + 1 :
10093                         i == Ykey_8_eat ? j + 1 :
10094                         i == Ylenses_eat ? j + 1 :
10095                         i == Ymagnify_eat ? j + 1 :
10096                         i == Ygrass_eat ? j + 1 :
10097                         i == Ydirt_eat ? j + 1 :
10098                         i == Xamoeba_1 ? 0 :
10099                         i == Xamoeba_2 ? 1 :
10100                         i == Xamoeba_3 ? 2 :
10101                         i == Xamoeba_4 ? 3 :
10102                         i == Xamoeba_5 ? 0 :
10103                         i == Xamoeba_6 ? 1 :
10104                         i == Xamoeba_7 ? 2 :
10105                         i == Xamoeba_8 ? 3 :
10106                         i == Xexit_2 ? j + 8 :
10107                         i == Xexit_3 ? j + 16 :
10108                         i == Xdynamite_1 ? 0 :
10109                         i == Xdynamite_2 ? 8 :
10110                         i == Xdynamite_3 ? 16 :
10111                         i == Xdynamite_4 ? 24 :
10112                         i == Xsand_stonein_1 ? j + 1 :
10113                         i == Xsand_stonein_2 ? j + 9 :
10114                         i == Xsand_stonein_3 ? j + 17 :
10115                         i == Xsand_stonein_4 ? j + 25 :
10116                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10117                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10118                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10119                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10120                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10121                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10122                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10123                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10124                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10125                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10126                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10127                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10128                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10129                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10130                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10131                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10132                         i == Xboom_bug && j == 1 ? 2 :
10133                         i == Xboom_bug && j == 2 ? 2 :
10134                         i == Xboom_bug && j == 3 ? 4 :
10135                         i == Xboom_bug && j == 4 ? 4 :
10136                         i == Xboom_bug && j == 5 ? 2 :
10137                         i == Xboom_bug && j == 6 ? 2 :
10138                         i == Xboom_bug && j == 7 ? 0 :
10139                         i == Xboom_bomb && j == 1 ? 2 :
10140                         i == Xboom_bomb && j == 2 ? 2 :
10141                         i == Xboom_bomb && j == 3 ? 4 :
10142                         i == Xboom_bomb && j == 4 ? 4 :
10143                         i == Xboom_bomb && j == 5 ? 2 :
10144                         i == Xboom_bomb && j == 6 ? 2 :
10145                         i == Xboom_bomb && j == 7 ? 0 :
10146                         i == Xboom_android && j == 7 ? 6 :
10147                         i == Xboom_1 && j == 1 ? 2 :
10148                         i == Xboom_1 && j == 2 ? 2 :
10149                         i == Xboom_1 && j == 3 ? 4 :
10150                         i == Xboom_1 && j == 4 ? 4 :
10151                         i == Xboom_1 && j == 5 ? 6 :
10152                         i == Xboom_1 && j == 6 ? 6 :
10153                         i == Xboom_1 && j == 7 ? 8 :
10154                         i == Xboom_2 && j == 0 ? 8 :
10155                         i == Xboom_2 && j == 1 ? 8 :
10156                         i == Xboom_2 && j == 2 ? 10 :
10157                         i == Xboom_2 && j == 3 ? 10 :
10158                         i == Xboom_2 && j == 4 ? 10 :
10159                         i == Xboom_2 && j == 5 ? 12 :
10160                         i == Xboom_2 && j == 6 ? 12 :
10161                         i == Xboom_2 && j == 7 ? 12 :
10162                         special_animation && j == 4 ? 3 :
10163                         effective_action != action ? 0 :
10164                         j);
10165
10166       xxx_effective_action = effective_action;
10167       xxx_has_action_graphics = has_action_graphics;
10168     }
10169   }
10170 #endif
10171
10172   int frame = getAnimationFrame(g->anim_frames,
10173                                 g->anim_delay,
10174                                 g->anim_mode,
10175                                 g->anim_start_frame,
10176                                 sync_frame);
10177
10178
10179 #if 0
10180   return;
10181 #endif
10182
10183 #if 0
10184   if (frame_em == 7)
10185     return;
10186 #endif
10187
10188 #if 0
10189   int old_src_x = g_em->src_x;
10190   int old_src_y = g_em->src_y;
10191 #endif
10192
10193 #if 1
10194   getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
10195                       g->double_movement && is_backside);
10196 #else
10197   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10198                       &g_em->src_x, &g_em->src_y, FALSE);
10199 #endif
10200
10201
10202 #if 0
10203   if (tile == Ydiamond_stone)
10204     printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
10205            frame_em,
10206            g->anim_frames,
10207            g->anim_delay,
10208            g->anim_mode,
10209            g->anim_start_frame,
10210            sync_frame,
10211            frame,
10212            g_em->src_x, g_em->src_y,
10213            g_em->src_offset_x, g_em->src_offset_y,
10214            g_em->dst_offset_x, g_em->dst_offset_y,
10215            graphic);
10216 #endif
10217
10218
10219 #if 0
10220   return;
10221 #endif
10222
10223 #if 0
10224   if (frame_em == 7)
10225   {
10226     if (graphic == IMG_BUG_MOVING_RIGHT)
10227       printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
10228              g->double_movement, is_backside,
10229              old_src_x, old_src_y, g_em->src_x, g_em->src_y);
10230
10231     return;
10232   }
10233 #endif
10234
10235
10236 #if 0
10237   g_em->src_offset_x = 0;
10238   g_em->src_offset_y = 0;
10239   g_em->dst_offset_x = 0;
10240   g_em->dst_offset_y = 0;
10241   g_em->width  = TILEX;
10242   g_em->height = TILEY;
10243
10244   g_em->preserve_background = FALSE;
10245 #endif
10246
10247   /* (updating the "crumbled" graphic definitions is probably not really needed,
10248      as animations for crumbled graphics can't be longer than one EMC cycle) */
10249 #if 1
10250   set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10251                            sync_frame);
10252
10253 #else
10254
10255   g_em->crumbled_bitmap = NULL;
10256   g_em->crumbled_src_x = 0;
10257   g_em->crumbled_src_y = 0;
10258
10259   g_em->has_crumbled_graphics = FALSE;
10260
10261   if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10262   {
10263     int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10264                                            g_crumbled->anim_delay,
10265                                            g_crumbled->anim_mode,
10266                                            g_crumbled->anim_start_frame,
10267                                            sync_frame);
10268
10269     getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
10270                      &g_em->crumbled_src_x, &g_em->crumbled_src_y);
10271
10272     g_em->has_crumbled_graphics = TRUE;
10273   }
10274 #endif
10275
10276 #if 0
10277  {
10278    int effective_action = xxx_effective_action;
10279    int has_action_graphics = xxx_has_action_graphics;
10280
10281       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10282                                    effective_action == ACTION_MOVING  ||
10283                                    effective_action == ACTION_PUSHING ||
10284                                    effective_action == ACTION_EATING)) ||
10285           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10286                                     effective_action == ACTION_EMPTYING)))
10287       {
10288         int move_dir =
10289           (effective_action == ACTION_FALLING ||
10290            effective_action == ACTION_FILLING ||
10291            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10292         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10293         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10294         int num_steps = (i == Ydrip_s1  ? 16 :
10295                          i == Ydrip_s1B ? 16 :
10296                          i == Ydrip_s2  ? 16 :
10297                          i == Ydrip_s2B ? 16 :
10298                          i == Xsand_stonein_1 ? 32 :
10299                          i == Xsand_stonein_2 ? 32 :
10300                          i == Xsand_stonein_3 ? 32 :
10301                          i == Xsand_stonein_4 ? 32 :
10302                          i == Xsand_stoneout_1 ? 16 :
10303                          i == Xsand_stoneout_2 ? 16 : 8);
10304         int cx = ABS(dx) * (TILEX / num_steps);
10305         int cy = ABS(dy) * (TILEY / num_steps);
10306         int step_frame = (i == Ydrip_s2         ? j + 8 :
10307                           i == Ydrip_s2B        ? j + 8 :
10308                           i == Xsand_stonein_2  ? j + 8 :
10309                           i == Xsand_stonein_3  ? j + 16 :
10310                           i == Xsand_stonein_4  ? j + 24 :
10311                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10312         int step = (is_backside ? step_frame : num_steps - step_frame);
10313
10314         if (is_backside)        /* tile where movement starts */
10315         {
10316           if (dx < 0 || dy < 0)
10317           {
10318             g_em->src_offset_x = cx * step;
10319             g_em->src_offset_y = cy * step;
10320           }
10321           else
10322           {
10323             g_em->dst_offset_x = cx * step;
10324             g_em->dst_offset_y = cy * step;
10325           }
10326         }
10327         else                    /* tile where movement ends */
10328         {
10329           if (dx < 0 || dy < 0)
10330           {
10331             g_em->dst_offset_x = cx * step;
10332             g_em->dst_offset_y = cy * step;
10333           }
10334           else
10335           {
10336             g_em->src_offset_x = cx * step;
10337             g_em->src_offset_y = cy * step;
10338           }
10339         }
10340
10341         g_em->width  = TILEX - cx * step;
10342         g_em->height = TILEY - cy * step;
10343       }
10344
10345       /* create unique graphic identifier to decide if tile must be redrawn */
10346       /* bit 31 - 16 (16 bit): EM style graphic
10347          bit 15 - 12 ( 4 bit): EM style frame
10348          bit 11 -  6 ( 6 bit): graphic width
10349          bit  5 -  0 ( 6 bit): graphic height */
10350       g_em->unique_identifier =
10351         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10352  }
10353 #endif
10354
10355 }
10356
10357 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
10358                                   int player_nr, int anim, int frame_em)
10359 {
10360   int element   = player_mapping[player_nr][anim].element_rnd;
10361   int action    = player_mapping[player_nr][anim].action;
10362   int direction = player_mapping[player_nr][anim].direction;
10363   int graphic = (direction == MV_NONE ?
10364                  el_act2img(element, action) :
10365                  el_act_dir2img(element, action, direction));
10366   struct GraphicInfo *g = &graphic_info[graphic];
10367   int sync_frame;
10368
10369   InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
10370
10371   stored_player[player_nr].StepFrame = frame_em;
10372
10373   sync_frame = stored_player[player_nr].Frame;
10374
10375   int frame = getAnimationFrame(g->anim_frames,
10376                                 g->anim_delay,
10377                                 g->anim_mode,
10378                                 g->anim_start_frame,
10379                                 sync_frame);
10380
10381   getGraphicSourceExt(graphic, frame, &g_em->bitmap,
10382                       &g_em->src_x, &g_em->src_y, FALSE);
10383
10384 #if 0
10385   printf("::: %d: %d, %d [%d]\n",
10386          player_nr,
10387          stored_player[player_nr].Frame,
10388          stored_player[player_nr].StepFrame,
10389          FrameCounter);
10390 #endif
10391 }
10392
10393 void InitGraphicInfo_EM(void)
10394 {
10395 #if 0
10396   struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
10397   struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
10398 #endif
10399   int i, j, p;
10400
10401 #if DEBUG_EM_GFX
10402   int num_em_gfx_errors = 0;
10403
10404   if (graphic_info_em_object[0][0].bitmap == NULL)
10405   {
10406     /* EM graphics not yet initialized in em_open_all() */
10407
10408     return;
10409   }
10410
10411   printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
10412 #endif
10413
10414   /* always start with reliable default values */
10415   for (i = 0; i < TILE_MAX; i++)
10416   {
10417     object_mapping[i].element_rnd = EL_UNKNOWN;
10418     object_mapping[i].is_backside = FALSE;
10419     object_mapping[i].action = ACTION_DEFAULT;
10420     object_mapping[i].direction = MV_NONE;
10421   }
10422
10423   /* always start with reliable default values */
10424   for (p = 0; p < MAX_PLAYERS; p++)
10425   {
10426     for (i = 0; i < SPR_MAX; i++)
10427     {
10428       player_mapping[p][i].element_rnd = EL_UNKNOWN;
10429       player_mapping[p][i].action = ACTION_DEFAULT;
10430       player_mapping[p][i].direction = MV_NONE;
10431     }
10432   }
10433
10434   for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
10435   {
10436     int e = em_object_mapping_list[i].element_em;
10437
10438     object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
10439     object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
10440
10441     if (em_object_mapping_list[i].action != -1)
10442       object_mapping[e].action = em_object_mapping_list[i].action;
10443
10444     if (em_object_mapping_list[i].direction != -1)
10445       object_mapping[e].direction =
10446         MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
10447   }
10448
10449   for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
10450   {
10451     int a = em_player_mapping_list[i].action_em;
10452     int p = em_player_mapping_list[i].player_nr;
10453
10454     player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
10455
10456     if (em_player_mapping_list[i].action != -1)
10457       player_mapping[p][a].action = em_player_mapping_list[i].action;
10458
10459     if (em_player_mapping_list[i].direction != -1)
10460       player_mapping[p][a].direction =
10461         MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
10462   }
10463
10464   for (i = 0; i < TILE_MAX; i++)
10465   {
10466     int element = object_mapping[i].element_rnd;
10467     int action = object_mapping[i].action;
10468     int direction = object_mapping[i].direction;
10469     boolean is_backside = object_mapping[i].is_backside;
10470 #if 0
10471     boolean action_removing = (action == ACTION_DIGGING ||
10472                                action == ACTION_SNAPPING ||
10473                                action == ACTION_COLLECTING);
10474 #endif
10475     boolean action_exploding = ((action == ACTION_EXPLODING ||
10476                                  action == ACTION_SMASHED_BY_ROCK ||
10477                                  action == ACTION_SMASHED_BY_SPRING) &&
10478                                 element != EL_DIAMOND);
10479     boolean action_active = (action == ACTION_ACTIVE);
10480     boolean action_other = (action == ACTION_OTHER);
10481
10482     for (j = 0; j < 8; j++)
10483     {
10484 #if 1
10485       int effective_element = get_effective_element_EM(i, j);
10486 #else
10487       int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
10488                                j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
10489                                j < 7 ? element :
10490                                i == Xdrip_stretch ? element :
10491                                i == Xdrip_stretchB ? element :
10492                                i == Ydrip_s1 ? element :
10493                                i == Ydrip_s1B ? element :
10494                                i == Xball_1B ? element :
10495                                i == Xball_2 ? element :
10496                                i == Xball_2B ? element :
10497                                i == Yball_eat ? element :
10498                                i == Ykey_1_eat ? element :
10499                                i == Ykey_2_eat ? element :
10500                                i == Ykey_3_eat ? element :
10501                                i == Ykey_4_eat ? element :
10502                                i == Ykey_5_eat ? element :
10503                                i == Ykey_6_eat ? element :
10504                                i == Ykey_7_eat ? element :
10505                                i == Ykey_8_eat ? element :
10506                                i == Ylenses_eat ? element :
10507                                i == Ymagnify_eat ? element :
10508                                i == Ygrass_eat ? element :
10509                                i == Ydirt_eat ? element :
10510                                i == Yemerald_stone ? EL_EMERALD :
10511                                i == Ydiamond_stone ? EL_ROCK :
10512                                i == Xsand_stonein_1 ? element :
10513                                i == Xsand_stonein_2 ? element :
10514                                i == Xsand_stonein_3 ? element :
10515                                i == Xsand_stonein_4 ? element :
10516                                is_backside ? EL_EMPTY :
10517                                action_removing ? EL_EMPTY :
10518                                element);
10519 #endif
10520       int effective_action = (j < 7 ? action :
10521                               i == Xdrip_stretch ? action :
10522                               i == Xdrip_stretchB ? action :
10523                               i == Ydrip_s1 ? action :
10524                               i == Ydrip_s1B ? action :
10525                               i == Xball_1B ? action :
10526                               i == Xball_2 ? action :
10527                               i == Xball_2B ? action :
10528                               i == Yball_eat ? action :
10529                               i == Ykey_1_eat ? action :
10530                               i == Ykey_2_eat ? action :
10531                               i == Ykey_3_eat ? action :
10532                               i == Ykey_4_eat ? action :
10533                               i == Ykey_5_eat ? action :
10534                               i == Ykey_6_eat ? action :
10535                               i == Ykey_7_eat ? action :
10536                               i == Ykey_8_eat ? action :
10537                               i == Ylenses_eat ? action :
10538                               i == Ymagnify_eat ? action :
10539                               i == Ygrass_eat ? action :
10540                               i == Ydirt_eat ? action :
10541                               i == Xsand_stonein_1 ? action :
10542                               i == Xsand_stonein_2 ? action :
10543                               i == Xsand_stonein_3 ? action :
10544                               i == Xsand_stonein_4 ? action :
10545                               i == Xsand_stoneout_1 ? action :
10546                               i == Xsand_stoneout_2 ? action :
10547                               i == Xboom_android ? ACTION_EXPLODING :
10548                               action_exploding ? ACTION_EXPLODING :
10549                               action_active ? action :
10550                               action_other ? action :
10551                               ACTION_DEFAULT);
10552       int graphic = (el_act_dir2img(effective_element, effective_action,
10553                                     direction));
10554       int crumbled = (el_act_dir2crm(effective_element, effective_action,
10555                                      direction));
10556       int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
10557       int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
10558       boolean has_action_graphics = (graphic != base_graphic);
10559       boolean has_crumbled_graphics = (base_crumbled != base_graphic);
10560       struct GraphicInfo *g = &graphic_info[graphic];
10561 #if 0
10562       struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
10563 #endif
10564       struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10565       Bitmap *src_bitmap;
10566       int src_x, src_y;
10567       /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
10568       boolean special_animation = (action != ACTION_DEFAULT &&
10569                                    g->anim_frames == 3 &&
10570                                    g->anim_delay == 2 &&
10571                                    g->anim_mode & ANIM_LINEAR);
10572       int sync_frame = (i == Xdrip_stretch ? 7 :
10573                         i == Xdrip_stretchB ? 7 :
10574                         i == Ydrip_s2 ? j + 8 :
10575                         i == Ydrip_s2B ? j + 8 :
10576                         i == Xacid_1 ? 0 :
10577                         i == Xacid_2 ? 10 :
10578                         i == Xacid_3 ? 20 :
10579                         i == Xacid_4 ? 30 :
10580                         i == Xacid_5 ? 40 :
10581                         i == Xacid_6 ? 50 :
10582                         i == Xacid_7 ? 60 :
10583                         i == Xacid_8 ? 70 :
10584                         i == Xfake_acid_1 ? 0 :
10585                         i == Xfake_acid_2 ? 10 :
10586                         i == Xfake_acid_3 ? 20 :
10587                         i == Xfake_acid_4 ? 30 :
10588                         i == Xfake_acid_5 ? 40 :
10589                         i == Xfake_acid_6 ? 50 :
10590                         i == Xfake_acid_7 ? 60 :
10591                         i == Xfake_acid_8 ? 70 :
10592                         i == Xball_2 ? 7 :
10593                         i == Xball_2B ? j + 8 :
10594                         i == Yball_eat ? j + 1 :
10595                         i == Ykey_1_eat ? j + 1 :
10596                         i == Ykey_2_eat ? j + 1 :
10597                         i == Ykey_3_eat ? j + 1 :
10598                         i == Ykey_4_eat ? j + 1 :
10599                         i == Ykey_5_eat ? j + 1 :
10600                         i == Ykey_6_eat ? j + 1 :
10601                         i == Ykey_7_eat ? j + 1 :
10602                         i == Ykey_8_eat ? j + 1 :
10603                         i == Ylenses_eat ? j + 1 :
10604                         i == Ymagnify_eat ? j + 1 :
10605                         i == Ygrass_eat ? j + 1 :
10606                         i == Ydirt_eat ? j + 1 :
10607                         i == Xamoeba_1 ? 0 :
10608                         i == Xamoeba_2 ? 1 :
10609                         i == Xamoeba_3 ? 2 :
10610                         i == Xamoeba_4 ? 3 :
10611                         i == Xamoeba_5 ? 0 :
10612                         i == Xamoeba_6 ? 1 :
10613                         i == Xamoeba_7 ? 2 :
10614                         i == Xamoeba_8 ? 3 :
10615                         i == Xexit_2 ? j + 8 :
10616                         i == Xexit_3 ? j + 16 :
10617                         i == Xdynamite_1 ? 0 :
10618                         i == Xdynamite_2 ? 8 :
10619                         i == Xdynamite_3 ? 16 :
10620                         i == Xdynamite_4 ? 24 :
10621                         i == Xsand_stonein_1 ? j + 1 :
10622                         i == Xsand_stonein_2 ? j + 9 :
10623                         i == Xsand_stonein_3 ? j + 17 :
10624                         i == Xsand_stonein_4 ? j + 25 :
10625                         i == Xsand_stoneout_1 && j == 0 ? 0 :
10626                         i == Xsand_stoneout_1 && j == 1 ? 0 :
10627                         i == Xsand_stoneout_1 && j == 2 ? 1 :
10628                         i == Xsand_stoneout_1 && j == 3 ? 2 :
10629                         i == Xsand_stoneout_1 && j == 4 ? 2 :
10630                         i == Xsand_stoneout_1 && j == 5 ? 3 :
10631                         i == Xsand_stoneout_1 && j == 6 ? 4 :
10632                         i == Xsand_stoneout_1 && j == 7 ? 4 :
10633                         i == Xsand_stoneout_2 && j == 0 ? 5 :
10634                         i == Xsand_stoneout_2 && j == 1 ? 6 :
10635                         i == Xsand_stoneout_2 && j == 2 ? 7 :
10636                         i == Xsand_stoneout_2 && j == 3 ? 8 :
10637                         i == Xsand_stoneout_2 && j == 4 ? 9 :
10638                         i == Xsand_stoneout_2 && j == 5 ? 11 :
10639                         i == Xsand_stoneout_2 && j == 6 ? 13 :
10640                         i == Xsand_stoneout_2 && j == 7 ? 15 :
10641                         i == Xboom_bug && j == 1 ? 2 :
10642                         i == Xboom_bug && j == 2 ? 2 :
10643                         i == Xboom_bug && j == 3 ? 4 :
10644                         i == Xboom_bug && j == 4 ? 4 :
10645                         i == Xboom_bug && j == 5 ? 2 :
10646                         i == Xboom_bug && j == 6 ? 2 :
10647                         i == Xboom_bug && j == 7 ? 0 :
10648                         i == Xboom_bomb && j == 1 ? 2 :
10649                         i == Xboom_bomb && j == 2 ? 2 :
10650                         i == Xboom_bomb && j == 3 ? 4 :
10651                         i == Xboom_bomb && j == 4 ? 4 :
10652                         i == Xboom_bomb && j == 5 ? 2 :
10653                         i == Xboom_bomb && j == 6 ? 2 :
10654                         i == Xboom_bomb && j == 7 ? 0 :
10655                         i == Xboom_android && j == 7 ? 6 :
10656                         i == Xboom_1 && j == 1 ? 2 :
10657                         i == Xboom_1 && j == 2 ? 2 :
10658                         i == Xboom_1 && j == 3 ? 4 :
10659                         i == Xboom_1 && j == 4 ? 4 :
10660                         i == Xboom_1 && j == 5 ? 6 :
10661                         i == Xboom_1 && j == 6 ? 6 :
10662                         i == Xboom_1 && j == 7 ? 8 :
10663                         i == Xboom_2 && j == 0 ? 8 :
10664                         i == Xboom_2 && j == 1 ? 8 :
10665                         i == Xboom_2 && j == 2 ? 10 :
10666                         i == Xboom_2 && j == 3 ? 10 :
10667                         i == Xboom_2 && j == 4 ? 10 :
10668                         i == Xboom_2 && j == 5 ? 12 :
10669                         i == Xboom_2 && j == 6 ? 12 :
10670                         i == Xboom_2 && j == 7 ? 12 :
10671                         special_animation && j == 4 ? 3 :
10672                         effective_action != action ? 0 :
10673                         j);
10674
10675 #if DEBUG_EM_GFX
10676       Bitmap *debug_bitmap = g_em->bitmap;
10677       int debug_src_x = g_em->src_x;
10678       int debug_src_y = g_em->src_y;
10679 #endif
10680
10681       int frame = getAnimationFrame(g->anim_frames,
10682                                     g->anim_delay,
10683                                     g->anim_mode,
10684                                     g->anim_start_frame,
10685                                     sync_frame);
10686
10687       getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
10688                           g->double_movement && is_backside);
10689
10690       g_em->bitmap = src_bitmap;
10691       g_em->src_x = src_x;
10692       g_em->src_y = src_y;
10693       g_em->src_offset_x = 0;
10694       g_em->src_offset_y = 0;
10695       g_em->dst_offset_x = 0;
10696       g_em->dst_offset_y = 0;
10697       g_em->width  = TILEX;
10698       g_em->height = TILEY;
10699
10700       g_em->preserve_background = FALSE;
10701
10702 #if 1
10703       set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
10704                                sync_frame);
10705
10706 #else
10707
10708       g_em->crumbled_bitmap = NULL;
10709       g_em->crumbled_src_x = 0;
10710       g_em->crumbled_src_y = 0;
10711       g_em->crumbled_border_size = 0;
10712
10713       g_em->has_crumbled_graphics = FALSE;
10714
10715 #if 0
10716       if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
10717         printf("::: empty crumbled: %d [%s], %d, %d\n",
10718                effective_element, element_info[effective_element].token_name,
10719                effective_action, direction);
10720 #endif
10721
10722       /* if element can be crumbled, but certain action graphics are just empty
10723          space (like instantly snapping sand to empty space in 1 frame), do not
10724          treat these empty space graphics as crumbled graphics in EMC engine */
10725       if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
10726       {
10727         int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
10728                                                g_crumbled->anim_delay,
10729                                                g_crumbled->anim_mode,
10730                                                g_crumbled->anim_start_frame,
10731                                                sync_frame);
10732
10733         getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
10734
10735         g_em->has_crumbled_graphics = TRUE;
10736         g_em->crumbled_bitmap = src_bitmap;
10737         g_em->crumbled_src_x = src_x;
10738         g_em->crumbled_src_y = src_y;
10739         g_em->crumbled_border_size = graphic_info[crumbled].border_size;
10740
10741
10742 #if 0
10743         if (g_em == &graphic_info_em_object[207][0])
10744           printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
10745                  graphic_info_em_object[207][0].crumbled_src_x,
10746                  graphic_info_em_object[207][0].crumbled_src_y,
10747
10748                  crumbled, frame, src_x, src_y,
10749
10750                  g->anim_frames,
10751                  g->anim_delay,
10752                  g->anim_mode,
10753                  g->anim_start_frame,
10754                  sync_frame,
10755                  gfx.anim_random_frame,
10756                  frame);
10757 #endif
10758
10759 #if 0
10760         printf("::: EMC tile %d is crumbled\n", i);
10761 #endif
10762       }
10763 #endif
10764
10765 #if 0
10766       if (element == EL_ROCK &&
10767           effective_action == ACTION_FILLING)
10768         printf("::: has_action_graphics == %d\n", has_action_graphics);
10769 #endif
10770
10771       if ((!g->double_movement && (effective_action == ACTION_FALLING ||
10772                                    effective_action == ACTION_MOVING  ||
10773                                    effective_action == ACTION_PUSHING ||
10774                                    effective_action == ACTION_EATING)) ||
10775           (!has_action_graphics && (effective_action == ACTION_FILLING ||
10776                                     effective_action == ACTION_EMPTYING)))
10777       {
10778         int move_dir =
10779           (effective_action == ACTION_FALLING ||
10780            effective_action == ACTION_FILLING ||
10781            effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
10782         int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
10783         int dy = (move_dir == MV_UP   ? -1 : move_dir == MV_DOWN  ? 1 : 0);
10784         int num_steps = (i == Ydrip_s1  ? 16 :
10785                          i == Ydrip_s1B ? 16 :
10786                          i == Ydrip_s2  ? 16 :
10787                          i == Ydrip_s2B ? 16 :
10788                          i == Xsand_stonein_1 ? 32 :
10789                          i == Xsand_stonein_2 ? 32 :
10790                          i == Xsand_stonein_3 ? 32 :
10791                          i == Xsand_stonein_4 ? 32 :
10792                          i == Xsand_stoneout_1 ? 16 :
10793                          i == Xsand_stoneout_2 ? 16 : 8);
10794         int cx = ABS(dx) * (TILEX / num_steps);
10795         int cy = ABS(dy) * (TILEY / num_steps);
10796         int step_frame = (i == Ydrip_s2         ? j + 8 :
10797                           i == Ydrip_s2B        ? j + 8 :
10798                           i == Xsand_stonein_2  ? j + 8 :
10799                           i == Xsand_stonein_3  ? j + 16 :
10800                           i == Xsand_stonein_4  ? j + 24 :
10801                           i == Xsand_stoneout_2 ? j + 8 : j) + 1;
10802         int step = (is_backside ? step_frame : num_steps - step_frame);
10803
10804         if (is_backside)        /* tile where movement starts */
10805         {
10806           if (dx < 0 || dy < 0)
10807           {
10808             g_em->src_offset_x = cx * step;
10809             g_em->src_offset_y = cy * step;
10810           }
10811           else
10812           {
10813             g_em->dst_offset_x = cx * step;
10814             g_em->dst_offset_y = cy * step;
10815           }
10816         }
10817         else                    /* tile where movement ends */
10818         {
10819           if (dx < 0 || dy < 0)
10820           {
10821             g_em->dst_offset_x = cx * step;
10822             g_em->dst_offset_y = cy * step;
10823           }
10824           else
10825           {
10826             g_em->src_offset_x = cx * step;
10827             g_em->src_offset_y = cy * step;
10828           }
10829         }
10830
10831         g_em->width  = TILEX - cx * step;
10832         g_em->height = TILEY - cy * step;
10833       }
10834
10835       /* create unique graphic identifier to decide if tile must be redrawn */
10836       /* bit 31 - 16 (16 bit): EM style graphic
10837          bit 15 - 12 ( 4 bit): EM style frame
10838          bit 11 -  6 ( 6 bit): graphic width
10839          bit  5 -  0 ( 6 bit): graphic height */
10840       g_em->unique_identifier =
10841         (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
10842
10843 #if DEBUG_EM_GFX
10844
10845       /* skip check for EMC elements not contained in original EMC artwork */
10846       if (element == EL_EMC_FAKE_ACID)
10847         continue;
10848
10849       if (g_em->bitmap != debug_bitmap ||
10850           g_em->src_x != debug_src_x ||
10851           g_em->src_y != debug_src_y ||
10852           g_em->src_offset_x != 0 ||
10853           g_em->src_offset_y != 0 ||
10854           g_em->dst_offset_x != 0 ||
10855           g_em->dst_offset_y != 0 ||
10856           g_em->width != TILEX ||
10857           g_em->height != TILEY)
10858       {
10859         static int last_i = -1;
10860
10861         if (i != last_i)
10862         {
10863           printf("\n");
10864           last_i = i;
10865         }
10866
10867         printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
10868                i, element, element_info[element].token_name,
10869                element_action_info[effective_action].suffix, direction);
10870
10871         if (element != effective_element)
10872           printf(" [%d ('%s')]",
10873                  effective_element,
10874                  element_info[effective_element].token_name);
10875
10876         printf("\n");
10877
10878         if (g_em->bitmap != debug_bitmap)
10879           printf("    %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
10880                  j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
10881
10882         if (g_em->src_x != debug_src_x ||
10883             g_em->src_y != debug_src_y)
10884           printf("    frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
10885                  j, (is_backside ? 'B' : 'F'),
10886                  g_em->src_x, g_em->src_y,
10887                  g_em->src_x / 32, g_em->src_y / 32,
10888                  debug_src_x, debug_src_y,
10889                  debug_src_x / 32, debug_src_y / 32);
10890
10891         if (g_em->src_offset_x != 0 ||
10892             g_em->src_offset_y != 0 ||
10893             g_em->dst_offset_x != 0 ||
10894             g_em->dst_offset_y != 0)
10895           printf("    %d (%d): offsets %d,%d and %d,%d should be all 0\n",
10896                  j, is_backside,
10897                  g_em->src_offset_x, g_em->src_offset_y,
10898                  g_em->dst_offset_x, g_em->dst_offset_y);
10899
10900         if (g_em->width != TILEX ||
10901             g_em->height != TILEY)
10902           printf("    %d (%d): size %d,%d should be %d,%d\n",
10903                  j, is_backside,
10904                  g_em->width, g_em->height, TILEX, TILEY);
10905
10906         num_em_gfx_errors++;
10907       }
10908 #endif
10909
10910     }
10911   }
10912
10913   for (i = 0; i < TILE_MAX; i++)
10914   {
10915     for (j = 0; j < 8; j++)
10916     {
10917       int element = object_mapping[i].element_rnd;
10918       int action = object_mapping[i].action;
10919       int direction = object_mapping[i].direction;
10920       boolean is_backside = object_mapping[i].is_backside;
10921       int graphic_action  = el_act_dir2img(element, action, direction);
10922       int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
10923
10924       if ((action == ACTION_SMASHED_BY_ROCK ||
10925            action == ACTION_SMASHED_BY_SPRING ||
10926            action == ACTION_EATING) &&
10927           graphic_action == graphic_default)
10928       {
10929         int e = (action == ACTION_SMASHED_BY_ROCK   ? Ystone_s  :
10930                  action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
10931                  direction == MV_LEFT  ? (is_backside? Yspring_wB: Yspring_w) :
10932                  direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
10933                  Xspring);
10934
10935         /* no separate animation for "smashed by rock" -- use rock instead */
10936         struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
10937         struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
10938
10939         g_em->bitmap            = g_xx->bitmap;
10940         g_em->src_x             = g_xx->src_x;
10941         g_em->src_y             = g_xx->src_y;
10942         g_em->src_offset_x      = g_xx->src_offset_x;
10943         g_em->src_offset_y      = g_xx->src_offset_y;
10944         g_em->dst_offset_x      = g_xx->dst_offset_x;
10945         g_em->dst_offset_y      = g_xx->dst_offset_y;
10946         g_em->width             = g_xx->width;
10947         g_em->height            = g_xx->height;
10948         g_em->unique_identifier = g_xx->unique_identifier;
10949
10950         if (!is_backside)
10951           g_em->preserve_background = TRUE;
10952       }
10953     }
10954   }
10955
10956   for (p = 0; p < MAX_PLAYERS; p++)
10957   {
10958     for (i = 0; i < SPR_MAX; i++)
10959     {
10960       int element = player_mapping[p][i].element_rnd;
10961       int action = player_mapping[p][i].action;
10962       int direction = player_mapping[p][i].direction;
10963
10964       for (j = 0; j < 8; j++)
10965       {
10966         int effective_element = element;
10967         int effective_action = action;
10968         int graphic = (direction == MV_NONE ?
10969                        el_act2img(effective_element, effective_action) :
10970                        el_act_dir2img(effective_element, effective_action,
10971                                       direction));
10972         struct GraphicInfo *g = &graphic_info[graphic];
10973         struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
10974         Bitmap *src_bitmap;
10975         int src_x, src_y;
10976         int sync_frame = j;
10977
10978 #if DEBUG_EM_GFX
10979         Bitmap *debug_bitmap = g_em->bitmap;
10980         int debug_src_x = g_em->src_x;
10981         int debug_src_y = g_em->src_y;
10982 #endif
10983
10984         int frame = getAnimationFrame(g->anim_frames,
10985                                       g->anim_delay,
10986                                       g->anim_mode,
10987                                       g->anim_start_frame,
10988                                       sync_frame);
10989
10990         getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
10991
10992         g_em->bitmap = src_bitmap;
10993         g_em->src_x = src_x;
10994         g_em->src_y = src_y;
10995         g_em->src_offset_x = 0;
10996         g_em->src_offset_y = 0;
10997         g_em->dst_offset_x = 0;
10998         g_em->dst_offset_y = 0;
10999         g_em->width  = TILEX;
11000         g_em->height = TILEY;
11001
11002 #if DEBUG_EM_GFX
11003
11004         /* skip check for EMC elements not contained in original EMC artwork */
11005         if (element == EL_PLAYER_3 ||
11006             element == EL_PLAYER_4)
11007           continue;
11008
11009         if (g_em->bitmap != debug_bitmap ||
11010             g_em->src_x != debug_src_x ||
11011             g_em->src_y != debug_src_y)
11012         {
11013           static int last_i = -1;
11014
11015           if (i != last_i)
11016           {
11017             printf("\n");
11018             last_i = i;
11019           }
11020
11021           printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
11022                  p, i, element, element_info[element].token_name,
11023                  element_action_info[effective_action].suffix, direction);
11024
11025           if (element != effective_element)
11026             printf(" [%d ('%s')]",
11027                    effective_element,
11028                    element_info[effective_element].token_name);
11029
11030           printf("\n");
11031
11032           if (g_em->bitmap != debug_bitmap)
11033             printf("    %d: different bitmap! (0x%08x != 0x%08x)\n",
11034                    j, (int)(g_em->bitmap), (int)(debug_bitmap));
11035
11036           if (g_em->src_x != debug_src_x ||
11037               g_em->src_y != debug_src_y)
11038             printf("    frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
11039                    j,
11040                    g_em->src_x, g_em->src_y,
11041                    g_em->src_x / 32, g_em->src_y / 32,
11042                    debug_src_x, debug_src_y,
11043                    debug_src_x / 32, debug_src_y / 32);
11044
11045           num_em_gfx_errors++;
11046         }
11047 #endif
11048
11049       }
11050     }
11051   }
11052
11053 #if DEBUG_EM_GFX
11054   printf("\n");
11055   printf("::: [%d errors found]\n", num_em_gfx_errors);
11056
11057   exit(0);
11058 #endif
11059 }
11060
11061 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
11062                             boolean any_player_moving,
11063                             boolean player_is_dropping)
11064 {
11065   if (tape.single_step && tape.recording && !tape.pausing)
11066   {
11067 #if 0
11068     boolean active_players = FALSE;
11069     int i;
11070
11071     for (i = 0; i < MAX_PLAYERS; i++)
11072       if (action[i] != JOY_NO_ACTION)
11073         active_players = TRUE;
11074 #endif
11075
11076     // if (frame == 0)
11077     if (frame == 0 && !player_is_dropping)
11078       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11079   }
11080 }
11081
11082 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
11083                             boolean murphy_is_dropping)
11084 {
11085 #if 0
11086   printf("::: waiting: %d, dropping: %d\n",
11087          murphy_is_waiting, murphy_is_dropping);
11088 #endif
11089
11090   if (tape.single_step && tape.recording && !tape.pausing)
11091   {
11092     // if (murphy_is_waiting || murphy_is_dropping)
11093     if (murphy_is_waiting)
11094     {
11095 #if 0
11096       printf("::: murphy is waiting -> pause mode\n");
11097 #endif
11098
11099       TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
11100     }
11101   }
11102 }
11103
11104 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
11105                          int graphic, int sync_frame, int x, int y)
11106 {
11107   int frame = getGraphicAnimationFrame(graphic, sync_frame);
11108
11109   getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
11110 }
11111
11112 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
11113 {
11114   return (IS_NEXT_FRAME(sync_frame, graphic));
11115 }
11116
11117 int getGraphicInfo_Delay(int graphic)
11118 {
11119   return graphic_info[graphic].anim_delay;
11120 }
11121
11122 void PlayMenuSoundExt(int sound)
11123 {
11124   if (sound == SND_UNDEFINED)
11125     return;
11126
11127   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11128       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11129     return;
11130
11131   if (IS_LOOP_SOUND(sound))
11132     PlaySoundLoop(sound);
11133   else
11134     PlaySound(sound);
11135 }
11136
11137 void PlayMenuSound()
11138 {
11139   PlayMenuSoundExt(menu.sound[game_status]);
11140 }
11141
11142 void PlayMenuSoundStereo(int sound, int stereo_position)
11143 {
11144   if (sound == SND_UNDEFINED)
11145     return;
11146
11147   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11148       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11149     return;
11150
11151   if (IS_LOOP_SOUND(sound))
11152     PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
11153   else
11154     PlaySoundStereo(sound, stereo_position);
11155 }
11156
11157 void PlayMenuSoundIfLoopExt(int sound)
11158 {
11159   if (sound == SND_UNDEFINED)
11160     return;
11161
11162   if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
11163       (!setup.sound_loops && IS_LOOP_SOUND(sound)))
11164     return;
11165
11166   if (IS_LOOP_SOUND(sound))
11167     PlaySoundLoop(sound);
11168 }
11169
11170 void PlayMenuSoundIfLoop()
11171 {
11172   PlayMenuSoundIfLoopExt(menu.sound[game_status]);
11173 }
11174
11175 void PlayMenuMusicExt(int music)
11176 {
11177   if (music == MUS_UNDEFINED)
11178     return;
11179
11180   if (!setup.sound_music)
11181     return;
11182
11183   PlayMusic(music);
11184 }
11185
11186 void PlayMenuMusic()
11187 {
11188   PlayMenuMusicExt(menu.music[game_status]);
11189 }
11190
11191 void PlaySoundActivating()
11192 {
11193 #if 0
11194   PlaySound(SND_MENU_ITEM_ACTIVATING);
11195 #endif
11196 }
11197
11198 void PlaySoundSelecting()
11199 {
11200 #if 0
11201   PlaySound(SND_MENU_ITEM_SELECTING);
11202 #endif
11203 }
11204
11205 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
11206 {
11207   boolean change_fullscreen = (setup.fullscreen !=
11208                                video.fullscreen_enabled);
11209   boolean change_fullscreen_mode = (video.fullscreen_enabled &&
11210                                     !strEqual(setup.fullscreen_mode,
11211                                               video.fullscreen_mode_current));
11212   boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
11213                                            setup.window_scaling_percent !=
11214                                            video.window_scaling_percent);
11215
11216   if (change_window_scaling_percent && video.fullscreen_enabled)
11217     return;
11218
11219   if (!change_window_scaling_percent && !video.fullscreen_available)
11220     return;
11221
11222 #if defined(TARGET_SDL2)
11223   if (change_window_scaling_percent)
11224   {
11225     SDLSetWindowScaling(setup.window_scaling_percent);
11226
11227     return;
11228   }
11229   else if (change_fullscreen)
11230   {
11231     SDLSetWindowFullscreen(setup.fullscreen);
11232
11233     /* set setup value according to successfully changed fullscreen mode */
11234     setup.fullscreen = video.fullscreen_enabled;
11235
11236     return;
11237   }
11238 #endif
11239
11240   if (change_fullscreen ||
11241       change_fullscreen_mode ||
11242       change_window_scaling_percent)
11243   {
11244     Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
11245
11246     /* save backbuffer content which gets lost when toggling fullscreen mode */
11247     BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11248
11249     if (change_fullscreen_mode)
11250     {
11251       /* keep fullscreen, but change fullscreen mode (screen resolution) */
11252       video.fullscreen_enabled = FALSE;         /* force new fullscreen mode */
11253     }
11254
11255     if (change_window_scaling_percent)
11256     {
11257       /* keep window mode, but change window scaling */
11258       video.fullscreen_enabled = TRUE;          /* force new window scaling */
11259     }
11260
11261     /* toggle fullscreen */
11262     ChangeVideoModeIfNeeded(setup.fullscreen);
11263
11264     /* set setup value according to successfully changed fullscreen mode */
11265     setup.fullscreen = video.fullscreen_enabled;
11266
11267     /* restore backbuffer content from temporary backbuffer backup bitmap */
11268     BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11269
11270     FreeBitmap(tmp_backbuffer);
11271
11272 #if 1
11273     /* update visible window/screen */
11274     BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
11275 #else
11276     redraw_mask = REDRAW_ALL;
11277 #endif
11278   }
11279 }
11280
11281 void ChangeViewportPropertiesIfNeeded()
11282 {
11283 #if 0
11284   int *door_1_x = &DX;
11285   int *door_1_y = &DY;
11286   int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
11287   int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
11288 #endif
11289 #if 1
11290   int gfx_game_mode = game_status;
11291 #else
11292   int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
11293                        game_status == GAME_MODE_EDITOR ? game_status :
11294                        GAME_MODE_MAIN);
11295 #endif
11296   int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
11297                         game_status);
11298   struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
11299   struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
11300   struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
11301   struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
11302   int border_size       = vp_playfield->border_size;
11303   int new_sx            = vp_playfield->x + border_size;
11304   int new_sy            = vp_playfield->y + border_size;
11305   int new_sxsize        = vp_playfield->width  - 2 * border_size;
11306   int new_sysize        = vp_playfield->height - 2 * border_size;
11307   int new_real_sx       = vp_playfield->x;
11308   int new_real_sy       = vp_playfield->y;
11309   int new_full_sxsize   = vp_playfield->width;
11310   int new_full_sysize   = vp_playfield->height;
11311   int new_dx            = vp_door_1->x;
11312   int new_dy            = vp_door_1->y;
11313   int new_dxsize        = vp_door_1->width;
11314   int new_dysize        = vp_door_1->height;
11315   int new_vx            = vp_door_2->x;
11316   int new_vy            = vp_door_2->y;
11317   int new_vxsize        = vp_door_2->width;
11318   int new_vysize        = vp_door_2->height;
11319   int new_ex            = vp_door_3->x;
11320   int new_ey            = vp_door_3->y;
11321   int new_exsize        = vp_door_3->width;
11322   int new_eysize        = vp_door_3->height;
11323 #if NEW_TILESIZE
11324   int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
11325   int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
11326                   gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
11327   int new_scr_fieldx = new_sxsize / tilesize;
11328   int new_scr_fieldy = new_sysize / tilesize;
11329   int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
11330   int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
11331 #else
11332   int new_scr_fieldx = (vp_playfield->width  - 2 * border_size) / TILESIZE;
11333   int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
11334 #endif
11335   boolean init_gfx_buffers = FALSE;
11336   boolean init_video_buffer = FALSE;
11337   boolean init_gadgets_and_toons = FALSE;
11338
11339 #if 0
11340   /* !!! TEST ONLY !!! */
11341   // InitGfxBuffers();
11342   return;
11343 #endif
11344
11345   if (viewport.window.width  != WIN_XSIZE ||
11346       viewport.window.height != WIN_YSIZE)
11347   {
11348     WIN_XSIZE = viewport.window.width;
11349     WIN_YSIZE = viewport.window.height;
11350
11351 #if 1
11352     init_video_buffer = TRUE;
11353     init_gfx_buffers = TRUE;
11354 #else
11355     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11356     InitGfxBuffers();
11357
11358 #if 1
11359     SetDrawDeactivationMask(REDRAW_NONE);
11360     SetDrawBackgroundMask(REDRAW_FIELD);
11361
11362     // RedrawBackground();
11363 #endif
11364 #endif
11365
11366     // printf("::: video: init_video_buffer, init_gfx_buffers\n");
11367   }
11368
11369   if (new_scr_fieldx != SCR_FIELDX ||
11370       new_scr_fieldy != SCR_FIELDY)
11371   {
11372     /* this always toggles between MAIN and GAME when using small tile size */
11373
11374     SCR_FIELDX = new_scr_fieldx;
11375     SCR_FIELDY = new_scr_fieldy;
11376
11377     // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
11378   }
11379
11380 #if 0
11381   if (new_tilesize_var != TILESIZE_VAR &&
11382       gfx_game_mode == GAME_MODE_PLAYING)
11383   {
11384     /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
11385
11386     TILESIZE_VAR = new_tilesize_var;
11387
11388     init_gfx_buffers = TRUE;
11389
11390     // printf("::: tilesize: init_gfx_buffers\n");
11391   }
11392 #endif
11393
11394   if (new_sx != SX ||
11395       new_sy != SY ||
11396       new_dx != DX ||
11397       new_dy != DY ||
11398       new_vx != VX ||
11399       new_vy != VY ||
11400       new_ex != EX ||
11401       new_ey != EY ||
11402       new_sxsize != SXSIZE ||
11403       new_sysize != SYSIZE ||
11404       new_dxsize != DXSIZE ||
11405       new_dysize != DYSIZE ||
11406       new_vxsize != VXSIZE ||
11407       new_vysize != VYSIZE ||
11408       new_exsize != EXSIZE ||
11409       new_eysize != EYSIZE ||
11410       new_real_sx != REAL_SX ||
11411       new_real_sy != REAL_SY ||
11412       new_full_sxsize != FULL_SXSIZE ||
11413       new_full_sysize != FULL_SYSIZE ||
11414       new_tilesize_var != TILESIZE_VAR
11415 #if 0
11416       ||
11417       vp_door_1->x != *door_1_x ||
11418       vp_door_1->y != *door_1_y ||
11419       vp_door_2->x != *door_2_x ||
11420       vp_door_2->y != *door_2_y
11421 #endif
11422       )
11423   {
11424     SX = new_sx;
11425     SY = new_sy;
11426     DX = new_dx;
11427     DY = new_dy;
11428     VX = new_vx;
11429     VY = new_vy;
11430     EX = new_ex;
11431     EY = new_ey;
11432     SXSIZE = new_sxsize;
11433     SYSIZE = new_sysize;
11434     DXSIZE = new_dxsize;
11435     DYSIZE = new_dysize;
11436     VXSIZE = new_vxsize;
11437     VYSIZE = new_vysize;
11438     EXSIZE = new_exsize;
11439     EYSIZE = new_eysize;
11440     REAL_SX = new_real_sx;
11441     REAL_SY = new_real_sy;
11442     FULL_SXSIZE = new_full_sxsize;
11443     FULL_SYSIZE = new_full_sysize;
11444     TILESIZE_VAR = new_tilesize_var;
11445
11446 #if 0
11447     printf("::: %d, %d, %d [%d]\n",
11448            SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
11449            setup.small_game_graphics);
11450 #endif
11451
11452 #if 0
11453     *door_1_x = vp_door_1->x;
11454     *door_1_y = vp_door_1->y;
11455     *door_2_x = vp_door_2->x;
11456     *door_2_y = vp_door_2->y;
11457 #endif
11458
11459 #if 1
11460     init_gfx_buffers = TRUE;
11461
11462     // printf("::: viewports: init_gfx_buffers\n");
11463 #else
11464     InitGfxBuffers();
11465 #endif
11466
11467 #if 0
11468     if (gfx_game_mode == GAME_MODE_MAIN)
11469 #endif
11470     {
11471 #if 1
11472       init_gadgets_and_toons = TRUE;
11473
11474       // printf("::: viewports: init_gadgets_and_toons\n");
11475 #else
11476       InitGadgets();
11477       InitToons();
11478 #endif
11479     }
11480   }
11481
11482   if (init_gfx_buffers)
11483   {
11484     // printf("::: init_gfx_buffers\n");
11485
11486     SCR_FIELDX = new_scr_fieldx_buffers;
11487     SCR_FIELDY = new_scr_fieldy_buffers;
11488
11489     InitGfxBuffers();
11490
11491     SCR_FIELDX = new_scr_fieldx;
11492     SCR_FIELDY = new_scr_fieldy;
11493   }
11494
11495   if (init_video_buffer)
11496   {
11497     // printf("::: init_video_buffer\n");
11498
11499     InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
11500
11501     SetDrawDeactivationMask(REDRAW_NONE);
11502     SetDrawBackgroundMask(REDRAW_FIELD);
11503   }
11504
11505   if (init_gadgets_and_toons)
11506   {
11507     // printf("::: init_gadgets_and_toons\n");
11508
11509     InitGadgets();
11510     InitToons();
11511   }
11512
11513 #if 0
11514   printf("::: %d, %d  /  %d, %d [%d]\n", VX, VY, EX, EY, game_status);
11515 #endif
11516 }