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