1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2006 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
26 /* select level set with EMC X11 graphics before activating EM GFX debugging */
27 #define DEBUG_EM_GFX 0
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
38 #define NUM_TOOL_BUTTONS 7
40 /* forward declaration for internal use */
41 static void UnmapToolButtons();
42 static void HandleToolButtons(struct GadgetInfo *);
43 static int el_act_dir2crm(int, int, int);
44 static int el_act2crm(int, int);
46 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
47 static int request_gadget_id = -1;
49 static char *print_if_not_empty(int element)
51 static char *s = NULL;
52 char *token_name = element_info[element].token_name;
57 s = checked_malloc(strlen(token_name) + 10 + 1);
59 if (element != EL_EMPTY)
60 sprintf(s, "%d\t['%s']", element, token_name);
62 sprintf(s, "%d", element);
67 void DumpTile(int x, int y)
72 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
79 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
82 if (!IN_LEV_FIELD(x, y))
84 printf("(not in level field)\n");
90 printf(" Feld: %d\t['%s']\n", Feld[x][y],
91 element_info[Feld[x][y]].token_name);
92 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
93 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
94 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
95 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
96 printf(" MovPos: %d\n", MovPos[x][y]);
97 printf(" MovDir: %d\n", MovDir[x][y]);
98 printf(" MovDelay: %d\n", MovDelay[x][y]);
99 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
100 printf(" CustomValue: %d\n", CustomValue[x][y]);
101 printf(" GfxElement: %d\n", GfxElement[x][y]);
102 printf(" GfxAction: %d\n", GfxAction[x][y]);
103 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
107 void SetDrawtoField(int mode)
109 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
117 BX2 = SCR_FIELDX + 1;
118 BY2 = SCR_FIELDY + 1;
137 BX2 = SCR_FIELDX + 1;
138 BY2 = SCR_FIELDY + 1;
153 drawto_field = fieldbuffer;
155 else /* DRAW_BACKBUFFER */
161 BX2 = SCR_FIELDX - 1;
162 BY2 = SCR_FIELDY - 1;
166 drawto_field = backbuffer;
170 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
172 if (game_status == GAME_MODE_PLAYING &&
173 level.game_engine_type == GAME_ENGINE_TYPE_EM)
175 /* currently there is no partial redraw -- always redraw whole playfield */
176 RedrawPlayfield_EM(TRUE);
178 /* blit playfield from scroll buffer to normal back buffer for fading in */
179 BlitScreenToBitmap_EM(backbuffer);
181 else if (game_status == GAME_MODE_PLAYING &&
182 level.game_engine_type == GAME_ENGINE_TYPE_SP)
184 /* currently there is no partial redraw -- always redraw whole playfield */
185 RedrawPlayfield_SP(TRUE);
187 /* blit playfield from scroll buffer to normal back buffer for fading in */
188 BlitScreenToBitmap_SP(backbuffer);
190 else if (game_status == GAME_MODE_PLAYING &&
191 !game.envelope_active)
197 width = gfx.sxsize + 2 * TILEX;
198 height = gfx.sysize + 2 * TILEY;
204 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
205 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
207 for (xx = BX1; xx <= BX2; xx++)
208 for (yy = BY1; yy <= BY2; yy++)
209 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
210 DrawScreenField(xx, yy);
214 if (setup.soft_scrolling)
216 int fx = FX, fy = FY;
218 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
219 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
221 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
233 BlitBitmap(drawto, window, x, y, width, height, x, y);
236 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
238 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
240 SetClipOrigin(bitmap, bitmap->stored_clip_gc, 0, 0);
241 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
244 void DrawMaskedBorder_FIELD()
246 if (global.border_status >= GAME_MODE_TITLE &&
247 global.border_status <= GAME_MODE_PLAYING &&
248 border.draw_masked[global.border_status])
249 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
252 void DrawMaskedBorder_DOOR_1()
254 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
255 (global.border_status != GAME_MODE_EDITOR ||
256 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
257 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
260 void DrawMaskedBorder_DOOR_2()
262 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
263 global.border_status != GAME_MODE_EDITOR)
264 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
267 void DrawMaskedBorder_DOOR_3()
269 /* currently not available */
272 void DrawMaskedBorder_ALL()
274 DrawMaskedBorder_FIELD();
275 DrawMaskedBorder_DOOR_1();
276 DrawMaskedBorder_DOOR_2();
277 DrawMaskedBorder_DOOR_3();
280 void DrawMaskedBorder(int redraw_mask)
282 /* never draw masked screen borders on borderless screens */
283 if (effectiveGameStatus() == GAME_MODE_LOADING ||
284 effectiveGameStatus() == GAME_MODE_TITLE)
287 /* never draw masked screen borders when displaying request outside door */
288 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
289 global.use_envelope_request)
292 if (redraw_mask & REDRAW_ALL)
293 DrawMaskedBorder_ALL();
296 if (redraw_mask & REDRAW_FIELD)
297 DrawMaskedBorder_FIELD();
298 if (redraw_mask & REDRAW_DOOR_1)
299 DrawMaskedBorder_DOOR_1();
300 if (redraw_mask & REDRAW_DOOR_2)
301 DrawMaskedBorder_DOOR_2();
302 if (redraw_mask & REDRAW_DOOR_3)
303 DrawMaskedBorder_DOOR_3();
307 void BlitScreenToBitmap(Bitmap *target_bitmap)
309 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
310 int fx = FX, fy = FY;
313 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
314 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
315 int dx_var = dx * TILESIZE_VAR / TILESIZE;
316 int dy_var = dy * TILESIZE_VAR / TILESIZE;
319 // fx += dx * TILESIZE_VAR / TILESIZE;
320 // fy += dy * TILESIZE_VAR / TILESIZE;
322 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
323 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
326 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
327 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
329 if (EVEN(SCR_FIELDX))
331 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
332 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
334 fx += (dx_var > 0 ? TILEX_VAR : 0);
341 if (EVEN(SCR_FIELDY))
343 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
344 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
346 fy += (dy_var > 0 ? TILEY_VAR : 0);
354 printf("::: (%d, %d) [(%d / %d, %d / %d)] => %d, %d\n",
357 SBY_Upper, SBY_Lower,
361 if (border.draw_masked[GAME_MODE_PLAYING])
363 if (buffer != backbuffer)
365 /* copy playfield buffer to backbuffer to add masked border */
366 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
367 DrawMaskedBorder(REDRAW_FIELD);
370 BlitBitmap(backbuffer, target_bitmap,
371 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
376 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
383 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
386 printf("::: TILES TO REFRESH: %d\n", redraw_tiles);
387 for (x = 0; x < SCR_FIELDX; x++)
388 for (y = 0 ; y < SCR_FIELDY; y++)
389 if (redraw[redraw_x1 + x][redraw_y1 + y])
390 printf("::: - %d, %d [%s]\n",
391 LEVELX(x), LEVELY(y),
392 EL_NAME(Feld[LEVELX(x)][LEVELY(y)]));
395 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
396 redraw_mask |= REDRAW_FIELD;
399 // never redraw single tiles, always redraw the whole field
400 // (redrawing single tiles up to a certain threshold was faster on old,
401 // now legacy graphics, but slows things down on modern graphics now)
402 // UPDATE: this is now globally defined by value of REDRAWTILES_THRESHOLD
403 if (redraw_mask & REDRAW_TILES)
404 redraw_mask |= REDRAW_FIELD;
408 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
409 /* (force full redraw) */
410 if (game_status == GAME_MODE_PLAYING)
411 redraw_mask |= REDRAW_FIELD;
414 if (redraw_mask & REDRAW_FIELD)
415 redraw_mask &= ~REDRAW_TILES;
417 if (redraw_mask == REDRAW_NONE)
422 if (redraw_mask & REDRAW_ALL)
423 printf("[REDRAW_ALL]");
424 if (redraw_mask & REDRAW_FIELD)
425 printf("[REDRAW_FIELD]");
426 if (redraw_mask & REDRAW_TILES)
427 printf("[REDRAW_TILES]");
428 if (redraw_mask & REDRAW_DOOR_1)
429 printf("[REDRAW_DOOR_1]");
430 if (redraw_mask & REDRAW_DOOR_2)
431 printf("[REDRAW_DOOR_2]");
432 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
433 printf("[REDRAW_FROM_BACKBUFFER]");
434 printf(" [%d]\n", FrameCounter);
437 if (redraw_mask & REDRAW_TILES &&
438 game_status == GAME_MODE_PLAYING &&
439 border.draw_masked[GAME_MODE_PLAYING])
440 redraw_mask |= REDRAW_FIELD;
442 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
444 static boolean last_frame_skipped = FALSE;
445 boolean skip_even_when_not_scrolling = TRUE;
446 boolean just_scrolling = (ScreenMovDir != 0);
447 boolean verbose = FALSE;
449 if (global.fps_slowdown_factor > 1 &&
450 (FrameCounter % global.fps_slowdown_factor) &&
451 (just_scrolling || skip_even_when_not_scrolling))
453 redraw_mask &= ~REDRAW_MAIN;
455 last_frame_skipped = TRUE;
458 printf("FRAME SKIPPED\n");
462 if (last_frame_skipped)
463 redraw_mask |= REDRAW_FIELD;
465 last_frame_skipped = FALSE;
468 printf("frame not skipped\n");
472 /* synchronize X11 graphics at this point; if we would synchronize the
473 display immediately after the buffer switching (after the XFlush),
474 this could mean that we have to wait for the graphics to complete,
475 although we could go on doing calculations for the next frame */
479 /* never draw masked border to backbuffer when using playfield buffer */
480 if (game_status != GAME_MODE_PLAYING ||
481 redraw_mask & REDRAW_FROM_BACKBUFFER ||
482 buffer == backbuffer)
483 DrawMaskedBorder(redraw_mask);
485 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
487 if (redraw_mask & REDRAW_ALL)
489 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
491 redraw_mask = REDRAW_NONE;
494 if (redraw_mask & REDRAW_FIELD)
497 printf("::: REDRAW_FIELD\n");
500 if (game_status != GAME_MODE_PLAYING ||
501 redraw_mask & REDRAW_FROM_BACKBUFFER)
503 BlitBitmap(backbuffer, window,
504 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
509 BlitScreenToBitmap(window);
511 int fx = FX, fy = FY;
514 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
515 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
516 int dx_var = dx * TILESIZE_VAR / TILESIZE;
517 int dy_var = dy * TILESIZE_VAR / TILESIZE;
520 // fx += dx * TILESIZE_VAR / TILESIZE;
521 // fy += dy * TILESIZE_VAR / TILESIZE;
523 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
524 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
527 /* !!! THIS WORKS !!! */
529 printf("::: %d, %d\n", scroll_x, scroll_y);
531 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
532 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
534 if (EVEN(SCR_FIELDX))
536 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
537 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
539 fx += (dx > 0 ? TILEX_VAR : 0);
546 if (EVEN(SCR_FIELDY))
548 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
549 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
551 fy += (dy > 0 ? TILEY_VAR : 0);
558 if (border.draw_masked[GAME_MODE_PLAYING])
560 if (buffer != backbuffer)
562 /* copy playfield buffer to backbuffer to add masked border */
563 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
564 DrawMaskedBorder(REDRAW_FIELD);
567 BlitBitmap(backbuffer, window,
568 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
573 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
579 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
581 (setup.soft_scrolling ?
582 "setup.soft_scrolling" :
583 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
584 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
585 ABS(ScreenGfxPos) == ScrollStepSize ?
586 "ABS(ScreenGfxPos) == ScrollStepSize" :
587 "redraw_tiles > REDRAWTILES_THRESHOLD"));
592 redraw_mask &= ~REDRAW_MAIN;
595 if (redraw_mask & REDRAW_DOORS)
597 if (redraw_mask & REDRAW_DOOR_1)
598 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
600 if (redraw_mask & REDRAW_DOOR_2)
601 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
603 if (redraw_mask & REDRAW_DOOR_3)
604 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
606 redraw_mask &= ~REDRAW_DOORS;
609 if (redraw_mask & REDRAW_MICROLEVEL)
611 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
612 SX, SY + 10 * TILEY);
614 redraw_mask &= ~REDRAW_MICROLEVEL;
617 if (redraw_mask & REDRAW_TILES)
620 printf("::: REDRAW_TILES\n");
626 InitGfxClipRegion(TRUE, SX, SY, SXSIZE, SYSIZE);
629 int sx = SX; // - (EVEN(SCR_FIELDX) ? TILEX_VAR / 2 : 0);
630 int sy = SY; // + (EVEN(SCR_FIELDY) ? TILEY_VAR / 2 : 0);
633 int dx_var = dx * TILESIZE_VAR / TILESIZE;
634 int dy_var = dy * TILESIZE_VAR / TILESIZE;
636 int fx = FX, fy = FY;
638 int scr_fieldx = SCR_FIELDX + (EVEN(SCR_FIELDX) ? 2 : 0);
639 int scr_fieldy = SCR_FIELDY + (EVEN(SCR_FIELDY) ? 2 : 0);
641 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
642 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
644 if (EVEN(SCR_FIELDX))
646 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
648 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
657 fx += (dx_var > 0 ? TILEX_VAR : 0);
661 if (EVEN(SCR_FIELDY))
663 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
665 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
674 fy += (dy_var > 0 ? TILEY_VAR : 0);
679 printf("::: %d, %d, %d, %d\n", sx, sy, SCR_FIELDX, SCR_FIELDY);
682 for (x = 0; x < scr_fieldx; x++)
683 for (y = 0 ; y < scr_fieldy; y++)
684 if (redraw[redraw_x1 + x][redraw_y1 + y])
685 BlitBitmap(buffer, window,
686 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
687 TILEX_VAR, TILEY_VAR,
688 sx + x * TILEX_VAR, sy + y * TILEY_VAR);
691 InitGfxClipRegion(FALSE, -1, -1, -1, -1);
693 for (x = 0; x < SCR_FIELDX; x++)
694 for (y = 0 ; y < SCR_FIELDY; y++)
695 if (redraw[redraw_x1 + x][redraw_y1 + y])
696 BlitBitmap(buffer, window,
697 FX + x * TILEX_VAR, FY + y * TILEY_VAR,
698 TILEX_VAR, TILEY_VAR,
699 SX + x * TILEX_VAR, SY + y * TILEY_VAR);
703 for (x = 0; x < SCR_FIELDX; x++)
704 for (y = 0 ; y < SCR_FIELDY; y++)
705 if (redraw[redraw_x1 + x][redraw_y1 + y])
706 BlitBitmap(buffer, window,
707 FX + x * TILEX, FY + y * TILEY, TILEX, TILEY,
708 SX + x * TILEX, SY + y * TILEY);
712 if (redraw_mask & REDRAW_FPS) /* display frames per second */
717 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
718 if (!global.fps_slowdown)
721 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
723 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
725 DrawTextExt(window, SX, SY, text, FONT_TEXT_2, BLIT_OPAQUE);
731 for (x = 0; x < MAX_BUF_XSIZE; x++)
732 for (y = 0; y < MAX_BUF_YSIZE; y++)
735 redraw_mask = REDRAW_NONE;
738 static void FadeCrossSaveBackbuffer()
740 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
743 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
745 static int fade_type_skip = FADE_TYPE_NONE;
746 void (*draw_border_function)(void) = NULL;
747 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
748 int x, y, width, height;
749 int fade_delay, post_delay;
751 if (fade_type == FADE_TYPE_FADE_OUT)
753 if (fade_type_skip != FADE_TYPE_NONE)
756 printf("::: skipping %d ... [%d] (X)\n", fade_mode, fade_type_skip);
759 /* skip all fade operations until specified fade operation */
760 if (fade_type & fade_type_skip)
761 fade_type_skip = FADE_TYPE_NONE;
766 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
768 FadeCrossSaveBackbuffer();
774 redraw_mask |= fade_mask;
776 if (fade_type == FADE_TYPE_SKIP)
779 printf("::: will skip %d ... [%d]\n", fade_mode, fade_type_skip);
782 fade_type_skip = fade_mode;
788 printf("::: !!! FADING %d ... [%d] [%d]\n", fade_mode, fade_type,
793 fade_delay = fading.fade_delay;
794 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
797 if (fade_type_skip != FADE_TYPE_NONE)
800 printf("::: skipping %d ... [%d]\n", fade_mode, fade_type_skip);
803 /* skip all fade operations until specified fade operation */
804 if (fade_type & fade_type_skip)
805 fade_type_skip = FADE_TYPE_NONE;
815 if (global.autoplay_leveldir)
817 // fading.fade_mode = FADE_MODE_NONE;
824 if (fading.fade_mode == FADE_MODE_NONE)
832 /* !!! what about fade_mask == REDRAW_FIELD | REDRAW_ALL ??? !!! */
835 printf("::: NOW FADING %d ... [%d]\n", fade_mode, fade_type);
839 if (fade_mask == REDRAW_NONE)
840 fade_mask = REDRAW_FIELD;
843 // if (fade_mask & REDRAW_FIELD)
844 if (fade_mask == REDRAW_FIELD)
849 height = FULL_SYSIZE;
852 fade_delay = fading.fade_delay;
853 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
856 if (border.draw_masked_when_fading)
857 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
859 DrawMaskedBorder_FIELD(); /* draw once */
861 else /* REDRAW_ALL */
869 fade_delay = fading.fade_delay;
870 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
875 if (!setup.fade_screens ||
877 fading.fade_mode == FADE_MODE_NONE)
879 if (!setup.fade_screens || fade_delay == 0)
882 if (fade_mode == FADE_MODE_FADE_OUT)
886 if (fade_mode == FADE_MODE_FADE_OUT &&
887 fading.fade_mode != FADE_MODE_NONE)
888 ClearRectangle(backbuffer, x, y, width, height);
892 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
893 redraw_mask = REDRAW_NONE;
901 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
902 draw_border_function);
904 redraw_mask &= ~fade_mask;
907 void FadeIn(int fade_mask)
909 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
910 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
912 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
915 void FadeOut(int fade_mask)
917 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
918 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
920 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
922 global.border_status = game_status;
925 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
927 static struct TitleFadingInfo fading_leave_stored;
930 fading_leave_stored = fading_leave;
932 fading = fading_leave_stored;
935 void FadeSetEnterMenu()
937 fading = menu.enter_menu;
940 printf("::: storing enter_menu\n");
943 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
946 void FadeSetLeaveMenu()
948 fading = menu.leave_menu;
951 printf("::: storing leave_menu\n");
954 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
957 void FadeSetEnterScreen()
959 fading = menu.enter_screen[game_status];
962 printf("::: storing leave_screen[%d]\n", game_status);
965 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
968 void FadeSetNextScreen()
970 fading = menu.next_screen;
973 printf("::: storing next_screen\n");
976 // (do not overwrite fade mode set by FadeSetEnterScreen)
977 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
980 void FadeSetLeaveScreen()
983 printf("::: recalling last stored value\n");
986 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
989 void FadeSetFromType(int type)
991 if (type & TYPE_ENTER_SCREEN)
992 FadeSetEnterScreen();
993 else if (type & TYPE_ENTER)
995 else if (type & TYPE_LEAVE)
999 void FadeSetDisabled()
1001 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
1003 fading = fading_none;
1006 void FadeSkipNextFadeIn()
1008 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
1011 void FadeSkipNextFadeOut()
1013 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
1016 void SetWindowBackgroundImageIfDefined(int graphic)
1018 if (graphic_info[graphic].bitmap)
1019 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
1022 void SetMainBackgroundImageIfDefined(int graphic)
1024 if (graphic_info[graphic].bitmap)
1025 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
1028 void SetDoorBackgroundImageIfDefined(int graphic)
1030 if (graphic_info[graphic].bitmap)
1031 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
1034 void SetWindowBackgroundImage(int graphic)
1036 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1037 graphic_info[graphic].bitmap ?
1038 graphic_info[graphic].bitmap :
1039 graphic_info[IMG_BACKGROUND].bitmap);
1042 void SetMainBackgroundImage(int graphic)
1044 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1045 graphic_info[graphic].bitmap ?
1046 graphic_info[graphic].bitmap :
1047 graphic_info[IMG_BACKGROUND].bitmap);
1050 void SetDoorBackgroundImage(int graphic)
1052 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
1053 graphic_info[graphic].bitmap ?
1054 graphic_info[graphic].bitmap :
1055 graphic_info[IMG_BACKGROUND].bitmap);
1058 void SetPanelBackground()
1061 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
1064 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1065 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
1067 /* (ClearRectangle() only needed if panel bitmap is smaller than panel) */
1068 ClearRectangle(bitmap_db_panel, DX, DY, DXSIZE, DYSIZE);
1069 BlitBitmap(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
1070 MIN(gfx->width, DXSIZE), MIN(gfx->height, DYSIZE), 0, 0);
1073 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, bitmap_db_panel,
1074 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, 0, 0);
1077 SetDoorBackgroundBitmap(bitmap_db_panel);
1080 void DrawBackground(int x, int y, int width, int height)
1082 /* !!! "drawto" might still point to playfield buffer here (see below) !!! */
1083 /* (when entering hall of fame after playing) */
1085 ClearRectangleOnBackground(drawto, x, y, width, height);
1087 ClearRectangleOnBackground(backbuffer, x, y, width, height);
1091 /* (this only works for the current arrangement of playfield and panels) */
1093 redraw_mask |= REDRAW_FIELD;
1094 else if (y < gfx.vy)
1095 redraw_mask |= REDRAW_DOOR_1;
1097 redraw_mask |= REDRAW_DOOR_2;
1099 /* (this is just wrong (when drawing to one of the two door panel areas)) */
1100 redraw_mask |= REDRAW_FIELD;
1104 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
1106 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
1108 if (font->bitmap == NULL)
1111 DrawBackground(x, y, width, height);
1114 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
1116 struct GraphicInfo *g = &graphic_info[graphic];
1118 if (g->bitmap == NULL)
1121 DrawBackground(x, y, width, height);
1126 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
1127 /* (when entering hall of fame after playing) */
1128 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
1130 /* !!! maybe this should be done before clearing the background !!! */
1131 if (setup.soft_scrolling && game_status == GAME_MODE_PLAYING)
1133 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
1134 SetDrawtoField(DRAW_BUFFERED);
1137 SetDrawtoField(DRAW_BACKBUFFER);
1140 void MarkTileDirty(int x, int y)
1142 int xx = redraw_x1 + x;
1143 int yy = redraw_y1 + y;
1145 if (!redraw[xx][yy])
1148 redraw[xx][yy] = TRUE;
1149 redraw_mask |= REDRAW_TILES;
1152 void SetBorderElement()
1156 BorderElement = EL_EMPTY;
1158 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
1160 for (x = 0; x < lev_fieldx; x++)
1162 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
1163 BorderElement = EL_STEELWALL;
1165 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
1171 void FloodFillLevel(int from_x, int from_y, int fill_element,
1172 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
1173 int max_fieldx, int max_fieldy)
1177 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
1178 static int safety = 0;
1180 /* check if starting field still has the desired content */
1181 if (field[from_x][from_y] == fill_element)
1186 if (safety > max_fieldx * max_fieldy)
1187 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
1189 old_element = field[from_x][from_y];
1190 field[from_x][from_y] = fill_element;
1192 for (i = 0; i < 4; i++)
1194 x = from_x + check[i][0];
1195 y = from_y + check[i][1];
1197 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
1198 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
1204 void SetRandomAnimationValue(int x, int y)
1206 gfx.anim_random_frame = GfxRandom[x][y];
1209 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
1211 /* animation synchronized with global frame counter, not move position */
1212 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
1213 sync_frame = FrameCounter;
1215 return getAnimationFrame(graphic_info[graphic].anim_frames,
1216 graphic_info[graphic].anim_delay,
1217 graphic_info[graphic].anim_mode,
1218 graphic_info[graphic].anim_start_frame,
1222 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize_raw,
1223 Bitmap **bitmap, int *x, int *y,
1224 boolean get_backside)
1228 int width_mult, width_div;
1229 int height_mult, height_div;
1233 { 15, 16, 2, 3 }, /* 1 x 1 */
1234 { 7, 8, 2, 3 }, /* 2 x 2 */
1235 { 3, 4, 2, 3 }, /* 4 x 4 */
1236 { 1, 2, 2, 3 }, /* 8 x 8 */
1237 { 0, 1, 2, 3 }, /* 16 x 16 */
1238 { 0, 1, 0, 1 }, /* 32 x 32 */
1240 struct GraphicInfo *g = &graphic_info[graphic];
1241 Bitmap *src_bitmap = g->bitmap;
1242 int tilesize = MIN(MAX(1, tilesize_raw), TILESIZE);
1243 int offset_calc_pos = log_2(tilesize);
1244 int width_mult = offset_calc[offset_calc_pos].width_mult;
1245 int width_div = offset_calc[offset_calc_pos].width_div;
1246 int height_mult = offset_calc[offset_calc_pos].height_mult;
1247 int height_div = offset_calc[offset_calc_pos].height_div;
1248 int startx = src_bitmap->width * width_mult / width_div;
1249 int starty = src_bitmap->height * height_mult / height_div;
1251 int src_x = (g->src_x + (get_backside ? g->offset2_x : 0)) *
1252 tilesize / TILESIZE;
1253 int src_y = (g->src_y + (get_backside ? g->offset2_y : 0)) *
1254 tilesize / TILESIZE;
1256 int src_x = g->src_x * tilesize / TILESIZE;
1257 int src_y = g->src_y * tilesize / TILESIZE;
1259 int width = g->width * tilesize / TILESIZE;
1260 int height = g->height * tilesize / TILESIZE;
1261 int offset_x = g->offset_x * tilesize / TILESIZE;
1262 int offset_y = g->offset_y * tilesize / TILESIZE;
1264 if (g->offset_y == 0) /* frames are ordered horizontally */
1266 int max_width = g->anim_frames_per_line * width;
1267 int pos = (src_y / height) * max_width + src_x + frame * offset_x;
1269 src_x = pos % max_width;
1270 src_y = src_y % height + pos / max_width * height;
1272 else if (g->offset_x == 0) /* frames are ordered vertically */
1274 int max_height = g->anim_frames_per_line * height;
1275 int pos = (src_x / width) * max_height + src_y + frame * offset_y;
1277 src_x = src_x % width + pos / max_height * width;
1278 src_y = pos % max_height;
1280 else /* frames are ordered diagonally */
1282 src_x = src_x + frame * offset_x;
1283 src_y = src_y + frame * offset_y;
1286 *bitmap = src_bitmap;
1287 *x = startx + src_x;
1288 *y = starty + src_y;
1291 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1292 int *x, int *y, boolean get_backside)
1294 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
1298 void getSizedGraphicSource(int graphic, int frame, int tilesize_raw,
1299 Bitmap **bitmap, int *x, int *y)
1301 getSizedGraphicSourceExt(graphic, frame, tilesize_raw, bitmap, x, y, FALSE);
1304 void getFixedGraphicSource(int graphic, int frame,
1305 Bitmap **bitmap, int *x, int *y)
1307 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1310 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1313 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1315 struct GraphicInfo *g = &graphic_info[graphic];
1316 int mini_startx = 0;
1317 int mini_starty = g->bitmap->height * 2 / 3;
1319 *bitmap = g->bitmap;
1320 *x = mini_startx + g->src_x / 2;
1321 *y = mini_starty + g->src_y / 2;
1325 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1326 int *x, int *y, boolean get_backside)
1328 struct GraphicInfo *g = &graphic_info[graphic];
1329 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1330 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1333 if (TILESIZE_VAR != TILESIZE)
1334 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1338 *bitmap = g->bitmap;
1340 if (g->offset_y == 0) /* frames are ordered horizontally */
1342 int max_width = g->anim_frames_per_line * g->width;
1343 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1345 *x = pos % max_width;
1346 *y = src_y % g->height + pos / max_width * g->height;
1348 else if (g->offset_x == 0) /* frames are ordered vertically */
1350 int max_height = g->anim_frames_per_line * g->height;
1351 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1353 *x = src_x % g->width + pos / max_height * g->width;
1354 *y = pos % max_height;
1356 else /* frames are ordered diagonally */
1358 *x = src_x + frame * g->offset_x;
1359 *y = src_y + frame * g->offset_y;
1363 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1365 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1368 void DrawGraphic(int x, int y, int graphic, int frame)
1371 if (!IN_SCR_FIELD(x, y))
1373 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1374 printf("DrawGraphic(): This should never happen!\n");
1380 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1383 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
1385 MarkTileDirty(x, y);
1388 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1391 if (!IN_SCR_FIELD(x, y))
1393 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1394 printf("DrawGraphic(): This should never happen!\n");
1399 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1401 MarkTileDirty(x, y);
1404 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1410 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1412 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1414 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1418 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1424 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1425 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1428 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1431 if (!IN_SCR_FIELD(x, y))
1433 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1434 printf("DrawGraphicThruMask(): This should never happen!\n");
1440 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1443 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1446 MarkTileDirty(x, y);
1449 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1452 if (!IN_SCR_FIELD(x, y))
1454 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1455 printf("DrawGraphicThruMask(): This should never happen!\n");
1460 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1462 MarkTileDirty(x, y);
1465 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1471 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1473 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1474 dst_x - src_x, dst_y - src_y);
1476 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1479 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1483 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1484 int graphic, int frame)
1489 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1491 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1492 dst_x - src_x, dst_y - src_y);
1493 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dst_x, dst_y);
1496 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1498 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1500 MarkTileDirty(x / tilesize, y / tilesize);
1503 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1509 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1510 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1513 void DrawMiniGraphic(int x, int y, int graphic)
1515 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1516 MarkTileDirty(x / 2, y / 2);
1519 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1524 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1525 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1528 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1529 int graphic, int frame,
1530 int cut_mode, int mask_mode)
1535 int width = TILEX, height = TILEY;
1538 if (dx || dy) /* shifted graphic */
1540 if (x < BX1) /* object enters playfield from the left */
1547 else if (x > BX2) /* object enters playfield from the right */
1553 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1559 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1561 else if (dx) /* general horizontal movement */
1562 MarkTileDirty(x + SIGN(dx), y);
1564 if (y < BY1) /* object enters playfield from the top */
1566 if (cut_mode==CUT_BELOW) /* object completely above top border */
1574 else if (y > BY2) /* object enters playfield from the bottom */
1580 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1586 else if (dy > 0 && cut_mode == CUT_ABOVE)
1588 if (y == BY2) /* object completely above bottom border */
1594 MarkTileDirty(x, y + 1);
1595 } /* object leaves playfield to the bottom */
1596 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1598 else if (dy) /* general vertical movement */
1599 MarkTileDirty(x, y + SIGN(dy));
1603 if (!IN_SCR_FIELD(x, y))
1605 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1606 printf("DrawGraphicShifted(): This should never happen!\n");
1612 width = width * TILESIZE_VAR / TILESIZE;
1613 height = height * TILESIZE_VAR / TILESIZE;
1614 cx = cx * TILESIZE_VAR / TILESIZE;
1615 cy = cy * TILESIZE_VAR / TILESIZE;
1616 dx = dx * TILESIZE_VAR / TILESIZE;
1617 dy = dy * TILESIZE_VAR / TILESIZE;
1620 if (width > 0 && height > 0)
1622 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1628 dst_x = FX + x * TILEX_VAR + dx;
1629 dst_y = FY + y * TILEY_VAR + dy;
1631 dst_x = FX + x * TILEX + dx;
1632 dst_y = FY + y * TILEY + dy;
1635 if (mask_mode == USE_MASKING)
1637 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1638 dst_x - src_x, dst_y - src_y);
1639 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1643 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1646 MarkTileDirty(x, y);
1650 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1651 int graphic, int frame,
1652 int cut_mode, int mask_mode)
1658 int width = TILEX_VAR, height = TILEY_VAR;
1660 int width = TILEX, height = TILEY;
1664 int x2 = x + SIGN(dx);
1665 int y2 = y + SIGN(dy);
1667 /* !!! DOES NOT WORK FOR SLOW MOVEMENT !!! */
1668 int sync_frame = GfxFrame[LEVELX(x)][LEVELY(y)];
1670 /* movement with two-tile animations must be sync'ed with movement position,
1671 not with current GfxFrame (which can be higher when using slow movement) */
1672 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1673 int anim_frames = graphic_info[graphic].anim_frames;
1675 /* (we also need anim_delay here for movement animations with less frames) */
1676 int anim_delay = graphic_info[graphic].anim_delay;
1677 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1679 int sync_frame = anim_pos * anim_frames / TILESIZE;
1682 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1683 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1685 /* re-calculate animation frame for two-tile movement animation */
1686 frame = getGraphicAnimationFrame(graphic, sync_frame);
1690 printf("::: %d, %d, %d => %d [%d]\n",
1691 anim_pos, anim_frames, anim_delay, sync_frame, graphic);
1693 printf("::: %d, %d => %d\n",
1694 anim_pos, anim_frames, sync_frame);
1699 printf("::: %d [%d, %d] [%d] [%d]\n", frame, sync_frame, dy,
1700 GfxFrame[LEVELX(x)][LEVELY(y)], mask_mode);
1703 /* check if movement start graphic inside screen area and should be drawn */
1704 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1706 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1709 dst_x = FX + x1 * TILEX_VAR;
1710 dst_y = FY + y1 * TILEY_VAR;
1712 dst_x = FX + x1 * TILEX;
1713 dst_y = FY + y1 * TILEY;
1716 if (mask_mode == USE_MASKING)
1718 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1719 dst_x - src_x, dst_y - src_y);
1720 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1724 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1727 MarkTileDirty(x1, y1);
1730 /* check if movement end graphic inside screen area and should be drawn */
1731 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1733 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1736 dst_x = FX + x2 * TILEX_VAR;
1737 dst_y = FY + y2 * TILEY_VAR;
1739 dst_x = FX + x2 * TILEX;
1740 dst_y = FY + y2 * TILEY;
1743 if (mask_mode == USE_MASKING)
1745 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
1746 dst_x - src_x, dst_y - src_y);
1747 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1751 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1754 MarkTileDirty(x2, y2);
1758 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1759 int graphic, int frame,
1760 int cut_mode, int mask_mode)
1764 DrawGraphic(x, y, graphic, frame);
1769 if (graphic_info[graphic].double_movement) /* EM style movement images */
1770 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1772 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1775 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1776 int frame, int cut_mode)
1778 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1781 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1782 int cut_mode, int mask_mode)
1784 int lx = LEVELX(x), ly = LEVELY(y);
1788 if (IN_LEV_FIELD(lx, ly))
1790 SetRandomAnimationValue(lx, ly);
1792 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1793 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1795 /* do not use double (EM style) movement graphic when not moving */
1796 if (graphic_info[graphic].double_movement && !dx && !dy)
1798 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1799 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1802 else /* border element */
1804 graphic = el2img(element);
1805 frame = getGraphicAnimationFrame(graphic, -1);
1808 if (element == EL_EXPANDABLE_WALL)
1810 boolean left_stopped = FALSE, right_stopped = FALSE;
1812 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1813 left_stopped = TRUE;
1814 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1815 right_stopped = TRUE;
1817 if (left_stopped && right_stopped)
1819 else if (left_stopped)
1821 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1822 frame = graphic_info[graphic].anim_frames - 1;
1824 else if (right_stopped)
1826 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1827 frame = graphic_info[graphic].anim_frames - 1;
1832 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1833 else if (mask_mode == USE_MASKING)
1834 DrawGraphicThruMask(x, y, graphic, frame);
1836 DrawGraphic(x, y, graphic, frame);
1839 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1840 int cut_mode, int mask_mode)
1842 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1843 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1844 cut_mode, mask_mode);
1847 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1850 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1853 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1856 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1859 void DrawLevelElementThruMask(int x, int y, int element)
1861 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1864 void DrawLevelFieldThruMask(int x, int y)
1866 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1869 /* !!! implementation of quicksand is totally broken !!! */
1870 #define IS_CRUMBLED_TILE(x, y, e) \
1871 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1872 !IS_MOVING(x, y) || \
1873 (e) == EL_QUICKSAND_EMPTYING || \
1874 (e) == EL_QUICKSAND_FAST_EMPTYING))
1876 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1881 int width, height, cx, cy;
1882 int sx = SCREENX(x), sy = SCREENY(y);
1883 int crumbled_border_size = graphic_info[graphic].border_size;
1886 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1888 for (i = 1; i < 4; i++)
1890 int dxx = (i & 1 ? dx : 0);
1891 int dyy = (i & 2 ? dy : 0);
1894 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1897 /* check if neighbour field is of same crumble type */
1898 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1899 graphic_info[graphic].class ==
1900 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1902 /* return if check prevents inner corner */
1903 if (same == (dxx == dx && dyy == dy))
1907 /* if we reach this point, we have an inner corner */
1909 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1912 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1913 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1914 cx = (dx > 0 ? TILEX - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1915 cy = (dy > 0 ? TILEY - crumbled_border_size : 0) * TILESIZE_VAR / TILESIZE;
1917 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1918 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1920 width = crumbled_border_size;
1921 height = crumbled_border_size;
1922 cx = (dx > 0 ? TILEX - crumbled_border_size : 0);
1923 cy = (dy > 0 ? TILEY - crumbled_border_size : 0);
1925 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1926 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1930 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1935 int width, height, bx, by, cx, cy;
1936 int sx = SCREENX(x), sy = SCREENY(y);
1937 int crumbled_border_size = graphic_info[graphic].border_size;
1940 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1942 /* draw simple, sloppy, non-corner-accurate crumbled border */
1945 width = (dir == 1 || dir == 2 ? crumbled_border_size : TILEX);
1946 height = (dir == 0 || dir == 3 ? crumbled_border_size : TILEY);
1947 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1948 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1950 if (dir == 1 || dir == 2) /* left or right crumbled border */
1952 width = crumbled_border_size;
1954 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
1957 else /* top or bottom crumbled border */
1960 height = crumbled_border_size;
1962 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
1967 BlitBitmap(src_bitmap, drawto_field,
1968 src_x + cx * TILESIZE_VAR / TILESIZE,
1969 src_y + cy * TILESIZE_VAR / TILESIZE,
1970 width * TILESIZE_VAR / TILESIZE,
1971 height * TILESIZE_VAR / TILESIZE,
1972 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
1973 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
1975 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1976 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
1979 /* (remaining middle border part must be at least as big as corner part) */
1980 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1981 crumbled_border_size >= TILESIZE / 3)
1984 /* correct corners of crumbled border, if needed */
1987 for (i = -1; i <= 1; i+=2)
1989 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1990 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1991 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1994 /* check if neighbour field is of same crumble type */
1995 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1996 graphic_info[graphic].class ==
1997 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1999 /* no crumbled corner, but continued crumbled border */
2001 int c1 = (dir == 2 || dir == 3 ? TILESIZE - crumbled_border_size : 0);
2002 int c2 = (i == 1 ? TILESIZE - crumbled_border_size : 0);
2003 int b1 = (i == 1 ? crumbled_border_size :
2004 TILESIZE - 2 * crumbled_border_size);
2006 width = crumbled_border_size;
2007 height = crumbled_border_size;
2009 if (dir == 1 || dir == 2)
2025 BlitBitmap(src_bitmap, drawto_field,
2026 src_x + bx * TILESIZE_VAR / TILESIZE,
2027 src_y + by * TILESIZE_VAR / TILESIZE,
2028 width * TILESIZE_VAR / TILESIZE,
2029 height * TILESIZE_VAR / TILESIZE,
2030 FX + sx * TILEX_VAR + cx * TILESIZE_VAR / TILESIZE,
2031 FY + sy * TILEY_VAR + cy * TILESIZE_VAR / TILESIZE);
2033 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2034 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2039 if (dir == 1 || dir == 2) /* left or right crumbled border */
2041 for (i = -1; i <= 1; i+=2)
2045 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2048 /* check if neighbour field is of same crumble type */
2049 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2050 graphic_info[graphic].class ==
2051 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2053 /* no crumbled corner, but continued crumbled border */
2055 width = crumbled_border_size;
2056 height = crumbled_border_size;
2057 cx = (dir == 2 ? TILEX - crumbled_border_size : 0);
2058 cy = (i == 1 ? TILEY - crumbled_border_size : 0);
2060 by = (i == 1 ? crumbled_border_size :
2061 TILEY - 2 * crumbled_border_size);
2063 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2064 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2068 else /* top or bottom crumbled border */
2070 for (i = -1; i <= 1; i+=2)
2074 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2077 /* check if neighbour field is of same crumble type */
2078 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2079 graphic_info[graphic].class ==
2080 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2082 /* no crumbled corner, but continued crumbled border */
2084 width = crumbled_border_size;
2085 height = crumbled_border_size;
2086 cx = (i == 1 ? TILEX - crumbled_border_size : 0);
2087 cy = (dir == 3 ? TILEY - crumbled_border_size : 0);
2088 bx = (i == 1 ? crumbled_border_size :
2089 TILEX - 2 * crumbled_border_size);
2092 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
2093 width, height, FX + sx * TILEX + cx, FY + sy * TILEY + cy);
2100 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
2102 int sx = SCREENX(x), sy = SCREENY(y);
2105 static int xy[4][2] =
2113 if (!IN_LEV_FIELD(x, y))
2116 element = TILE_GFX_ELEMENT(x, y);
2118 /* crumble field itself */
2119 if (IS_CRUMBLED_TILE(x, y, element))
2121 if (!IN_SCR_FIELD(sx, sy))
2124 for (i = 0; i < 4; i++)
2126 int xx = x + xy[i][0];
2127 int yy = y + xy[i][1];
2129 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
2132 /* check if neighbour field is of same crumble type */
2134 if (IS_CRUMBLED_TILE(xx, yy, element) &&
2135 graphic_info[graphic].class ==
2136 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
2139 if (IS_CRUMBLED_TILE(xx, yy, element))
2143 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
2146 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
2147 graphic_info[graphic].anim_frames == 2)
2149 for (i = 0; i < 4; i++)
2151 int dx = (i & 1 ? +1 : -1);
2152 int dy = (i & 2 ? +1 : -1);
2154 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
2158 MarkTileDirty(sx, sy);
2160 else /* center field not crumbled -- crumble neighbour fields */
2162 for (i = 0; i < 4; i++)
2164 int xx = x + xy[i][0];
2165 int yy = y + xy[i][1];
2166 int sxx = sx + xy[i][0];
2167 int syy = sy + xy[i][1];
2169 if (!IN_LEV_FIELD(xx, yy) ||
2170 !IN_SCR_FIELD(sxx, syy))
2173 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
2176 element = TILE_GFX_ELEMENT(xx, yy);
2178 if (!IS_CRUMBLED_TILE(xx, yy, element))
2181 graphic = el_act2crm(element, ACTION_DEFAULT);
2183 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
2185 MarkTileDirty(sxx, syy);
2190 void DrawLevelFieldCrumbled(int x, int y)
2194 if (!IN_LEV_FIELD(x, y))
2198 /* !!! CHECK THIS !!! */
2201 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2202 GFX_CRUMBLED(GfxElement[x][y]))
2205 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
2206 GfxElement[x][y] != EL_UNDEFINED &&
2207 GFX_CRUMBLED(GfxElement[x][y]))
2209 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
2216 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
2218 graphic = el_act2crm(Feld[x][y], ACTION_DEFAULT);
2221 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
2224 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
2227 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
2228 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
2229 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
2230 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
2231 int sx = SCREENX(x), sy = SCREENY(y);
2233 DrawGraphic(sx, sy, graphic1, frame1);
2234 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
2237 void DrawLevelFieldCrumbledNeighbours(int x, int y)
2239 int sx = SCREENX(x), sy = SCREENY(y);
2240 static int xy[4][2] =
2249 for (i = 0; i < 4; i++)
2251 int xx = x + xy[i][0];
2252 int yy = y + xy[i][1];
2253 int sxx = sx + xy[i][0];
2254 int syy = sy + xy[i][1];
2256 if (!IN_LEV_FIELD(xx, yy) ||
2257 !IN_SCR_FIELD(sxx, syy) ||
2258 !GFX_CRUMBLED(Feld[xx][yy]) ||
2262 DrawLevelField(xx, yy);
2266 static int getBorderElement(int x, int y)
2270 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
2271 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
2272 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
2273 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
2274 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
2275 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
2276 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
2278 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
2279 int steel_position = (x == -1 && y == -1 ? 0 :
2280 x == lev_fieldx && y == -1 ? 1 :
2281 x == -1 && y == lev_fieldy ? 2 :
2282 x == lev_fieldx && y == lev_fieldy ? 3 :
2283 x == -1 || x == lev_fieldx ? 4 :
2284 y == -1 || y == lev_fieldy ? 5 : 6);
2286 return border[steel_position][steel_type];
2289 void DrawScreenElement(int x, int y, int element)
2291 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
2292 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
2295 void DrawLevelElement(int x, int y, int element)
2297 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2298 DrawScreenElement(SCREENX(x), SCREENY(y), element);
2301 void DrawScreenField(int x, int y)
2303 int lx = LEVELX(x), ly = LEVELY(y);
2304 int element, content;
2306 if (!IN_LEV_FIELD(lx, ly))
2308 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
2311 element = getBorderElement(lx, ly);
2313 DrawScreenElement(x, y, element);
2318 element = Feld[lx][ly];
2319 content = Store[lx][ly];
2321 if (IS_MOVING(lx, ly))
2323 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
2324 boolean cut_mode = NO_CUTTING;
2326 if (element == EL_QUICKSAND_EMPTYING ||
2327 element == EL_QUICKSAND_FAST_EMPTYING ||
2328 element == EL_MAGIC_WALL_EMPTYING ||
2329 element == EL_BD_MAGIC_WALL_EMPTYING ||
2330 element == EL_DC_MAGIC_WALL_EMPTYING ||
2331 element == EL_AMOEBA_DROPPING)
2332 cut_mode = CUT_ABOVE;
2333 else if (element == EL_QUICKSAND_FILLING ||
2334 element == EL_QUICKSAND_FAST_FILLING ||
2335 element == EL_MAGIC_WALL_FILLING ||
2336 element == EL_BD_MAGIC_WALL_FILLING ||
2337 element == EL_DC_MAGIC_WALL_FILLING)
2338 cut_mode = CUT_BELOW;
2341 if (lx == 9 && ly == 1)
2342 printf("::: %s [%d] [%d, %d] [%d]\n",
2343 EL_NAME(TILE_GFX_ELEMENT(lx, ly)),
2344 el_act2crm(TILE_GFX_ELEMENT(lx, ly), ACTION_DEFAULT),
2345 element_info[EL_QUICKSAND_EMPTYING].graphic[ACTION_DEFAULT],
2346 element_info[EL_QUICKSAND_EMPTYING].crumbled[ACTION_DEFAULT],
2347 GFX_CRUMBLED(TILE_GFX_ELEMENT(lx, ly)));
2350 if (cut_mode == CUT_ABOVE)
2352 DrawScreenElement(x, y, element);
2354 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
2357 DrawScreenElement(x, y, EL_EMPTY);
2360 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
2361 else if (cut_mode == NO_CUTTING)
2362 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
2365 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
2368 if (cut_mode == CUT_BELOW &&
2369 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
2370 DrawLevelElement(lx, ly + 1, element);
2374 if (content == EL_ACID)
2376 int dir = MovDir[lx][ly];
2377 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2378 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2380 DrawLevelElementThruMask(newlx, newly, EL_ACID);
2383 else if (IS_BLOCKED(lx, ly))
2388 boolean cut_mode = NO_CUTTING;
2389 int element_old, content_old;
2391 Blocked2Moving(lx, ly, &oldx, &oldy);
2394 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
2395 MovDir[oldx][oldy] == MV_RIGHT);
2397 element_old = Feld[oldx][oldy];
2398 content_old = Store[oldx][oldy];
2400 if (element_old == EL_QUICKSAND_EMPTYING ||
2401 element_old == EL_QUICKSAND_FAST_EMPTYING ||
2402 element_old == EL_MAGIC_WALL_EMPTYING ||
2403 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
2404 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
2405 element_old == EL_AMOEBA_DROPPING)
2406 cut_mode = CUT_ABOVE;
2408 DrawScreenElement(x, y, EL_EMPTY);
2411 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
2413 else if (cut_mode == NO_CUTTING)
2414 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
2417 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
2420 else if (IS_DRAWABLE(element))
2421 DrawScreenElement(x, y, element);
2423 DrawScreenElement(x, y, EL_EMPTY);
2426 void DrawLevelField(int x, int y)
2428 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2429 DrawScreenField(SCREENX(x), SCREENY(y));
2430 else if (IS_MOVING(x, y))
2434 Moving2Blocked(x, y, &newx, &newy);
2435 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2436 DrawScreenField(SCREENX(newx), SCREENY(newy));
2438 else if (IS_BLOCKED(x, y))
2442 Blocked2Moving(x, y, &oldx, &oldy);
2443 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
2444 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
2448 void DrawMiniElement(int x, int y, int element)
2452 graphic = el2edimg(element);
2453 DrawMiniGraphic(x, y, graphic);
2456 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
2458 int x = sx + scroll_x, y = sy + scroll_y;
2460 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
2461 DrawMiniElement(sx, sy, EL_EMPTY);
2462 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
2463 DrawMiniElement(sx, sy, Feld[x][y]);
2465 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
2468 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
2469 int x, int y, int xsize, int ysize,
2470 int tile_width, int tile_height)
2474 int dst_x = startx + x * tile_width;
2475 int dst_y = starty + y * tile_height;
2476 int width = graphic_info[graphic].width;
2477 int height = graphic_info[graphic].height;
2478 int inner_width = MAX(width - 2 * tile_width, tile_width);
2479 int inner_height = MAX(height - 2 * tile_height, tile_height);
2480 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
2481 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
2482 boolean draw_masked = graphic_info[graphic].draw_masked;
2484 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
2486 if (src_bitmap == NULL || width < tile_width || height < tile_height)
2488 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
2492 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
2493 inner_sx + (x - 1) * tile_width % inner_width);
2494 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
2495 inner_sy + (y - 1) * tile_height % inner_height);
2499 SetClipOrigin(src_bitmap, src_bitmap->stored_clip_gc,
2500 dst_x - src_x, dst_y - src_y);
2501 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2505 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2509 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2510 int x, int y, int xsize, int ysize, int font_nr)
2512 int font_width = getFontWidth(font_nr);
2513 int font_height = getFontHeight(font_nr);
2515 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2516 font_width, font_height);
2519 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2521 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2522 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2523 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2524 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2525 boolean no_delay = (tape.warp_forward);
2526 unsigned int anim_delay = 0;
2527 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2528 int anim_delay_value = (no_delay ? 0 : frame_delay_value);
2529 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2530 int font_width = getFontWidth(font_nr);
2531 int font_height = getFontHeight(font_nr);
2532 int max_xsize = level.envelope[envelope_nr].xsize;
2533 int max_ysize = level.envelope[envelope_nr].ysize;
2534 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2535 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2536 int xend = max_xsize;
2537 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2538 int xstep = (xstart < xend ? 1 : 0);
2539 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2542 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2544 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2545 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2546 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2547 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2550 SetDrawtoField(DRAW_BUFFERED);
2553 BlitScreenToBitmap(backbuffer);
2555 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2558 SetDrawtoField(DRAW_BACKBUFFER);
2560 for (yy = 0; yy < ysize; yy++)
2561 for (xx = 0; xx < xsize; xx++)
2562 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2565 DrawTextBuffer(sx + font_width, sy + font_height,
2566 level.envelope[envelope_nr].text, font_nr, max_xsize,
2567 xsize - 2, ysize - 2, 0, mask_mode,
2568 level.envelope[envelope_nr].autowrap,
2569 level.envelope[envelope_nr].centered, FALSE);
2571 DrawTextToTextArea(sx + font_width, sy + font_height,
2572 level.envelope[envelope_nr].text, font_nr, max_xsize,
2573 xsize - 2, ysize - 2, mask_mode);
2576 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2579 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2583 void ShowEnvelope(int envelope_nr)
2585 int element = EL_ENVELOPE_1 + envelope_nr;
2586 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2587 int sound_opening = element_info[element].sound[ACTION_OPENING];
2588 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2589 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2590 boolean no_delay = (tape.warp_forward);
2591 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2592 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2593 int anim_mode = graphic_info[graphic].anim_mode;
2594 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2595 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2597 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2599 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2601 if (anim_mode == ANIM_DEFAULT)
2602 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2604 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2607 Delay(wait_delay_value);
2609 WaitForEventToContinue();
2611 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2613 if (anim_mode != ANIM_NONE)
2614 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2616 if (anim_mode == ANIM_DEFAULT)
2617 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2619 game.envelope_active = FALSE;
2621 SetDrawtoField(DRAW_BUFFERED);
2623 redraw_mask |= REDRAW_FIELD;
2627 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2629 int border_size = request.border_size;
2630 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2631 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2632 int sx = sx_center - request.width / 2;
2633 int sy = sy_center - request.height / 2;
2635 if (add_border_size)
2645 void DrawEnvelopeRequest(char *text)
2647 int graphic = IMG_BACKGROUND_REQUEST;
2648 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2649 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2650 int font_nr = FONT_REQUEST;
2651 int font_width = getFontWidth(font_nr);
2652 int font_height = getFontHeight(font_nr);
2653 int border_size = request.border_size;
2654 int line_spacing = request.line_spacing;
2655 int line_height = font_height + line_spacing;
2656 int text_width = request.width - 2 * border_size;
2657 int text_height = request.height - 2 * border_size;
2658 int line_length = text_width / font_width;
2659 int max_lines = text_height / line_height;
2660 boolean autowrap = FALSE;
2661 boolean centered = TRUE;
2662 int width = request.width;
2663 int height = request.height;
2664 int tile_size = request.step_offset;
2665 int x_steps = width / tile_size;
2666 int y_steps = height / tile_size;
2670 setRequestPosition(&sx, &sy, FALSE);
2672 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2674 for (y = 0; y < y_steps; y++)
2675 for (x = 0; x < x_steps; x++)
2676 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2677 x, y, x_steps, y_steps,
2678 tile_size, tile_size);
2680 DrawTextBuffer(sx + border_size, sy + border_size, text, font_nr,
2681 line_length, -1, max_lines, line_spacing, mask_mode,
2682 autowrap, centered, FALSE);
2684 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2685 RedrawGadget(tool_gadget[i]);
2687 // store readily prepared envelope request for later use when animating
2688 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2692 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2693 BlitBitmap(bitmap_db_cross, backbuffer, sx, sy, width, height, sx, sy);
2695 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2700 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2702 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2711 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2713 int graphic = IMG_BACKGROUND_REQUEST;
2714 boolean draw_masked = graphic_info[graphic].draw_masked;
2716 int delay_value_normal = request.step_delay;
2717 int delay_value_fast = delay_value_normal / 2;
2719 int delay_value_normal = GameFrameDelay;
2720 int delay_value_fast = FfwdFrameDelay;
2722 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2723 boolean no_delay = (tape.warp_forward);
2724 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2725 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0);
2726 unsigned int anim_delay = 0;
2728 int width = request.width;
2729 int height = request.height;
2730 int tile_size = request.step_offset;
2731 int max_xsize = width / tile_size;
2732 int max_ysize = height / tile_size;
2733 int max_xsize_inner = max_xsize - 2;
2734 int max_ysize_inner = max_ysize - 2;
2736 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2737 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2738 int xend = max_xsize_inner;
2739 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2740 int xstep = (xstart < xend ? 1 : 0);
2741 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2744 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2746 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2747 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2748 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2749 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2750 int src_x = sx_center - width / 2;
2751 int src_y = sy_center - height / 2;
2752 int dst_x = sx_center - xsize * tile_size / 2;
2753 int dst_y = sy_center - ysize * tile_size / 2;
2754 int xsize_size_left = (xsize - 1) * tile_size;
2755 int ysize_size_top = (ysize - 1) * tile_size;
2756 int max_xsize_pos = (max_xsize - 1) * tile_size;
2757 int max_ysize_pos = (max_ysize - 1) * tile_size;
2760 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2763 for (yy = 0; yy < 2; yy++)
2765 for (xx = 0; xx < 2; xx++)
2767 int src_xx = src_x + xx * max_xsize_pos;
2768 int src_yy = src_y + yy * max_ysize_pos;
2769 int dst_xx = dst_x + xx * xsize_size_left;
2770 int dst_yy = dst_y + yy * ysize_size_top;
2771 int xx_size = (xx ? tile_size : xsize_size_left);
2772 int yy_size = (yy ? tile_size : ysize_size_top);
2775 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2776 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2778 BlitBitmap(bitmap_db_cross, backbuffer,
2779 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2783 BlitBitmap(bitmap_db_cross, backbuffer,
2785 xsize_size_left, ysize_size_top,
2787 BlitBitmap(bitmap_db_cross, backbuffer,
2788 src_x + max_xsize_pos, src_y,
2789 tile_size, ysize_size_top,
2790 dst_x + xsize_size_left, dst_y);
2791 BlitBitmap(bitmap_db_cross, backbuffer,
2792 src_x, src_y + max_ysize_pos,
2793 xsize_size_left, tile_size,
2794 dst_x, dst_y + ysize_size_top);
2795 BlitBitmap(bitmap_db_cross, backbuffer,
2796 src_x + max_xsize_pos, src_y + max_ysize_pos,
2797 tile_size, tile_size,
2798 dst_x + xsize_size_left, dst_y + ysize_size_top);
2802 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2803 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
2805 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2815 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
2821 void AnimateEnvelopeRequest(char *text, int anim_mode, int action)
2824 int envelope_nr = 0;
2827 int graphic = IMG_BACKGROUND_REQUEST;
2829 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2831 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2832 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2833 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2834 boolean no_delay = (tape.warp_forward);
2835 unsigned int anim_delay = 0;
2836 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2837 int anim_delay_value = (no_delay ? 0 : frame_delay_value + 500 * 0);
2839 int max_word_len = maxWordLengthInString(text);
2840 int font_nr = (max_word_len > 7 ? FONT_TEXT_1 : FONT_TEXT_2);
2842 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2844 int font_width = getFontWidth(font_nr);
2845 int font_height = getFontHeight(font_nr);
2846 int line_spacing = 2 * 1;
2850 int max_xsize = DXSIZE / font_width;
2851 // int max_ysize = DYSIZE / font_height;
2852 int max_ysize = DYSIZE / (font_height + line_spacing);
2854 int max_xsize = 7; /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2855 int max_ysize = 13; /* tools.c: MAX_REQUEST_LINES == 13 */
2859 int max_xsize = level.envelope[envelope_nr].xsize;
2860 int max_ysize = level.envelope[envelope_nr].ysize;
2862 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2863 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2864 int xend = max_xsize;
2865 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2866 int xstep = (xstart < xend ? 1 : 0);
2867 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2872 char *text_copy = getStringCopy(text);
2875 font_nr = FONT_TEXT_2;
2877 if (maxWordLengthInString(text) > 7) /* MAX_REQUEST_LINE_FONT1_LEN == 7 */
2879 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2880 font_nr = FONT_TEXT_1;
2883 int max_word_len = 0;
2885 char *text_copy = getStringCopy(text);
2887 font_nr = FONT_TEXT_2;
2889 for (text_ptr = text; *text_ptr; text_ptr++)
2891 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
2893 if (max_word_len > 7) /* tools.c: MAX_REQUEST_LINE_FONT1_LEN == 7 */
2895 max_xsize = 10; /* tools.c: MAX_REQUEST_LINE_FONT2_LEN == 10 */
2896 font_nr = FONT_TEXT_1;
2905 for (text_ptr = text_copy; *text_ptr; text_ptr++)
2906 if (*text_ptr == ' ')
2911 dDX = SX + (SXSIZE - DXSIZE) / 2 - DX;
2912 dDY = SY + (SYSIZE - DYSIZE) / 2 - DY;
2914 dDX = SX + SXSIZE / 2 - max_xsize * font_width / 2 - DX;
2915 dDY = SY + SYSIZE / 2 - max_ysize * font_height / 2 - DY;
2918 for (x = xstart, y = ystart; x <= xend && y <= yend; x += xstep, y += ystep)
2920 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2921 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2922 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2923 // int sy = SX + (SYSIZE - ysize * font_height) / 2;
2924 int sy = SY + (SYSIZE - ysize * (font_height + line_spacing)) / 2;
2928 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2930 SetDrawtoField(DRAW_BUFFERED);
2933 BlitScreenToBitmap(backbuffer);
2935 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
2938 SetDrawtoField(DRAW_BACKBUFFER);
2941 for (yy = 0; yy < ysize; yy++)
2942 for (xx = 0; xx < xsize; xx++)
2943 DrawEnvelopeBackgroundTiles(graphic, sx, sy, xx, yy, xsize, ysize,
2944 getFontWidth(font_nr),
2945 getFontHeight(font_nr) + line_spacing);
2950 DrawTextBuffer(sx + font_width, sy + font_height + 8,
2951 text_copy, font_nr, max_xsize,
2952 xsize - 2, ysize - 2, line_spacing, mask_mode,
2953 FALSE, TRUE, FALSE);
2955 DrawTextBuffer(sx + font_width, sy + font_height,
2956 level.envelope[envelope_nr].text, font_nr, max_xsize,
2957 xsize - 2, ysize - 2, 0, mask_mode,
2958 level.envelope[envelope_nr].autowrap,
2959 level.envelope[envelope_nr].centered, FALSE);
2963 DrawTextToTextArea(sx + font_width, sy + font_height,
2964 level.envelope[envelope_nr].text, font_nr, max_xsize,
2965 xsize - 2, ysize - 2, mask_mode);
2968 /* copy request gadgets to door backbuffer */
2971 if ((ysize - 2) > 13)
2972 BlitBitmap(bitmap_db_door, drawto,
2973 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2974 DOOR_GFX_PAGEY1 + 13 * font_height,
2975 (xsize - 2) * font_width,
2976 (ysize - 2 - 13) * font_height,
2978 sy + font_height * (1 + 13));
2980 if ((ysize - 2) > 13)
2981 BlitBitmap(bitmap_db_door, drawto,
2982 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2983 DOOR_GFX_PAGEY1 + 11 * (font_height + line_spacing * 0),
2984 (xsize - 2) * font_width,
2985 (ysize - 2 - 13) * (font_height + line_spacing),
2987 sy + (font_height + line_spacing) * (1 + 13));
2989 if ((ysize - 2) > 13)
2990 BlitBitmap(bitmap_db_door, drawto,
2991 DOOR_GFX_PAGEX1 + (DXSIZE - (xsize - 2) * font_width) / 2,
2992 DOOR_GFX_PAGEY1 + 13 * font_height,
2993 (xsize - 2) * font_width,
2994 (ysize - 2 - 13) * font_height,
2996 sy + font_height * (1 + 13));
3000 redraw_mask = REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3001 // redraw_mask |= REDRAW_ALL | REDRAW_FROM_BACKBUFFER;
3003 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
3013 WaitUntilDelayReached(&anim_delay, anim_delay_value / 2);
3023 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
3026 int last_game_status = game_status; /* save current game status */
3027 // int last_draw_background_mask = gfx.draw_background_mask;
3030 int graphic = IMG_BACKGROUND_REQUEST;
3031 int sound_opening = SND_REQUEST_OPENING;
3032 int sound_closing = SND_REQUEST_CLOSING;
3034 int envelope_nr = 0;
3035 int element = EL_ENVELOPE_1 + envelope_nr;
3036 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
3037 int sound_opening = element_info[element].sound[ACTION_OPENING];
3038 int sound_closing = element_info[element].sound[ACTION_CLOSING];
3041 boolean ffwd_delay = (tape.playing && tape.fast_forward);
3042 boolean no_delay = (tape.warp_forward);
3043 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
3044 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
3046 int anim_mode = graphic_info[graphic].anim_mode;
3047 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
3048 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
3049 char *text_copy = getStringCopy(text);
3052 for (text_ptr = text_copy; *text_ptr; text_ptr++)
3053 if (*text_ptr == ' ')
3057 if (game_status == GAME_MODE_PLAYING)
3059 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
3060 BlitScreenToBitmap_EM(backbuffer);
3061 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
3062 BlitScreenToBitmap_SP(backbuffer);
3065 BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
3069 SetDrawtoField(DRAW_BACKBUFFER);
3071 // SetDrawBackgroundMask(REDRAW_NONE);
3073 if (action == ACTION_OPENING)
3075 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3078 if (req_state & REQ_ASK)
3080 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3081 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3083 else if (req_state & REQ_CONFIRM)
3085 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3087 else if (req_state & REQ_PLAYER)
3089 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3090 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3091 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3092 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3096 DrawEnvelopeRequest(text_copy);
3098 if (game_status != GAME_MODE_MAIN)
3102 /* force DOOR font inside door area */
3103 game_status = GAME_MODE_PSEUDO_DOOR;
3106 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
3108 if (action == ACTION_OPENING)
3110 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
3112 if (anim_mode == ANIM_DEFAULT)
3113 AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_OPENING);
3115 AnimateEnvelopeRequest(text, main_anim_mode, ACTION_OPENING);
3119 Delay(wait_delay_value);
3121 WaitForEventToContinue();
3126 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
3128 if (anim_mode != ANIM_NONE)
3129 AnimateEnvelopeRequest(text, main_anim_mode, ACTION_CLOSING);
3131 if (anim_mode == ANIM_DEFAULT)
3132 AnimateEnvelopeRequest(text, ANIM_DEFAULT, ACTION_CLOSING);
3135 game.envelope_active = FALSE;
3138 // game_status = last_game_status; /* restore current game status */
3140 if (action == ACTION_CLOSING)
3142 if (game_status != GAME_MODE_MAIN)
3145 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
3148 SetDrawtoField(DRAW_BUFFERED);
3151 // SetDrawBackgroundMask(last_draw_background_mask);
3154 redraw_mask = REDRAW_FIELD;
3155 // redraw_mask |= REDRAW_ALL;
3157 redraw_mask |= REDRAW_FIELD;
3161 if (game_status == GAME_MODE_MAIN)
3166 /* (important: after "BackToFront()", but before "SetDrawtoField()") */
3167 game_status = last_game_status; /* restore current game status */
3169 if (game_status == GAME_MODE_PLAYING &&
3170 level.game_engine_type == GAME_ENGINE_TYPE_RND)
3171 SetDrawtoField(DRAW_BUFFERED);
3179 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
3183 int graphic = el2preimg(element);
3185 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
3186 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
3194 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
3195 SetDrawBackgroundMask(REDRAW_FIELD);
3197 SetDrawBackgroundMask(REDRAW_NONE);
3202 for (x = BX1; x <= BX2; x++)
3203 for (y = BY1; y <= BY2; y++)
3204 DrawScreenField(x, y);
3206 redraw_mask |= REDRAW_FIELD;
3209 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
3213 for (x = 0; x < size_x; x++)
3214 for (y = 0; y < size_y; y++)
3215 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
3217 redraw_mask |= REDRAW_FIELD;
3220 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
3222 boolean show_level_border = (BorderElement != EL_EMPTY);
3223 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3224 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3225 int tile_size = preview.tile_size;
3226 int preview_width = preview.xsize * tile_size;
3227 int preview_height = preview.ysize * tile_size;
3228 int real_preview_xsize = MIN(level_xsize, preview.xsize);
3229 int real_preview_ysize = MIN(level_ysize, preview.ysize);
3230 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
3231 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
3234 DrawBackground(dst_x, dst_y, preview_width, preview_height);
3236 dst_x += (preview_width - real_preview_xsize * tile_size) / 2;
3237 dst_y += (preview_height - real_preview_ysize * tile_size) / 2;
3239 for (x = 0; x < real_preview_xsize; x++)
3241 for (y = 0; y < real_preview_ysize; y++)
3243 int lx = from_x + x + (show_level_border ? -1 : 0);
3244 int ly = from_y + y + (show_level_border ? -1 : 0);
3245 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
3246 getBorderElement(lx, ly));
3248 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
3249 element, tile_size);
3253 redraw_mask |= REDRAW_MICROLEVEL;
3256 #define MICROLABEL_EMPTY 0
3257 #define MICROLABEL_LEVEL_NAME 1
3258 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
3259 #define MICROLABEL_LEVEL_AUTHOR 3
3260 #define MICROLABEL_IMPORTED_FROM_HEAD 4
3261 #define MICROLABEL_IMPORTED_FROM 5
3262 #define MICROLABEL_IMPORTED_BY_HEAD 6
3263 #define MICROLABEL_IMPORTED_BY 7
3265 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
3267 int max_text_width = SXSIZE;
3268 int font_width = getFontWidth(font_nr);
3270 if (pos->align == ALIGN_CENTER)
3271 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
3272 else if (pos->align == ALIGN_RIGHT)
3273 max_text_width = pos->x;
3275 max_text_width = SXSIZE - pos->x;
3277 return max_text_width / font_width;
3280 static void DrawPreviewLevelLabelExt(int mode)
3282 struct TextPosInfo *pos = &menu.main.text.level_info_2;
3283 char label_text[MAX_OUTPUT_LINESIZE + 1];
3284 int max_len_label_text;
3286 int font_nr = pos->font;
3289 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3290 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3291 mode == MICROLABEL_IMPORTED_BY_HEAD)
3292 font_nr = pos->font_alt;
3294 int font_nr = FONT_TEXT_2;
3297 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
3298 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
3299 mode == MICROLABEL_IMPORTED_BY_HEAD)
3300 font_nr = FONT_TEXT_3;
3304 max_len_label_text = getMaxTextLength(pos, font_nr);
3306 max_len_label_text = SXSIZE / getFontWidth(font_nr);
3310 if (pos->size != -1)
3311 max_len_label_text = pos->size;
3314 for (i = 0; i < max_len_label_text; i++)
3315 label_text[i] = ' ';
3316 label_text[max_len_label_text] = '\0';
3318 if (strlen(label_text) > 0)
3321 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3323 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3324 int lypos = MICROLABEL2_YPOS;
3326 DrawText(lxpos, lypos, label_text, font_nr);
3331 (mode == MICROLABEL_LEVEL_NAME ? level.name :
3332 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
3333 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
3334 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
3335 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
3336 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
3337 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
3338 max_len_label_text);
3339 label_text[max_len_label_text] = '\0';
3341 if (strlen(label_text) > 0)
3344 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3346 int lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3347 int lypos = MICROLABEL2_YPOS;
3349 DrawText(lxpos, lypos, label_text, font_nr);
3353 redraw_mask |= REDRAW_MICROLEVEL;
3356 static void DrawPreviewLevelExt(boolean restart)
3358 static unsigned int scroll_delay = 0;
3359 static unsigned int label_delay = 0;
3360 static int from_x, from_y, scroll_direction;
3361 static int label_state, label_counter;
3362 unsigned int scroll_delay_value = preview.step_delay;
3363 boolean show_level_border = (BorderElement != EL_EMPTY);
3364 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
3365 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
3366 int last_game_status = game_status; /* save current game status */
3369 /* force PREVIEW font on preview level */
3370 game_status = GAME_MODE_PSEUDO_PREVIEW;
3378 if (preview.anim_mode == ANIM_CENTERED)
3380 if (level_xsize > preview.xsize)
3381 from_x = (level_xsize - preview.xsize) / 2;
3382 if (level_ysize > preview.ysize)
3383 from_y = (level_ysize - preview.ysize) / 2;
3386 from_x += preview.xoffset;
3387 from_y += preview.yoffset;
3389 scroll_direction = MV_RIGHT;
3393 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3394 DrawPreviewLevelLabelExt(label_state);
3396 /* initialize delay counters */
3397 DelayReached(&scroll_delay, 0);
3398 DelayReached(&label_delay, 0);
3400 if (leveldir_current->name)
3402 struct TextPosInfo *pos = &menu.main.text.level_info_1;
3403 char label_text[MAX_OUTPUT_LINESIZE + 1];
3405 int font_nr = pos->font;
3407 int font_nr = FONT_TEXT_1;
3410 int max_len_label_text = getMaxTextLength(pos, font_nr);
3412 int max_len_label_text = SXSIZE / getFontWidth(font_nr);
3420 if (pos->size != -1)
3421 max_len_label_text = pos->size;
3424 strncpy(label_text, leveldir_current->name, max_len_label_text);
3425 label_text[max_len_label_text] = '\0';
3428 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
3430 lxpos = SX + (SXSIZE - getTextWidth(label_text, font_nr)) / 2;
3431 lypos = SY + MICROLABEL1_YPOS;
3433 DrawText(lxpos, lypos, label_text, font_nr);
3437 game_status = last_game_status; /* restore current game status */
3442 /* scroll preview level, if needed */
3443 if (preview.anim_mode != ANIM_NONE &&
3444 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
3445 DelayReached(&scroll_delay, scroll_delay_value))
3447 switch (scroll_direction)
3452 from_x -= preview.step_offset;
3453 from_x = (from_x < 0 ? 0 : from_x);
3456 scroll_direction = MV_UP;
3460 if (from_x < level_xsize - preview.xsize)
3462 from_x += preview.step_offset;
3463 from_x = (from_x > level_xsize - preview.xsize ?
3464 level_xsize - preview.xsize : from_x);
3467 scroll_direction = MV_DOWN;
3473 from_y -= preview.step_offset;
3474 from_y = (from_y < 0 ? 0 : from_y);
3477 scroll_direction = MV_RIGHT;
3481 if (from_y < level_ysize - preview.ysize)
3483 from_y += preview.step_offset;
3484 from_y = (from_y > level_ysize - preview.ysize ?
3485 level_ysize - preview.ysize : from_y);
3488 scroll_direction = MV_LEFT;
3495 DrawPreviewLevelPlayfieldExt(from_x, from_y);
3498 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
3499 /* redraw micro level label, if needed */
3500 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
3501 !strEqual(level.author, ANONYMOUS_NAME) &&
3502 !strEqual(level.author, leveldir_current->name) &&
3503 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
3505 int max_label_counter = 23;
3507 if (leveldir_current->imported_from != NULL &&
3508 strlen(leveldir_current->imported_from) > 0)
3509 max_label_counter += 14;
3510 if (leveldir_current->imported_by != NULL &&
3511 strlen(leveldir_current->imported_by) > 0)
3512 max_label_counter += 14;
3514 label_counter = (label_counter + 1) % max_label_counter;
3515 label_state = (label_counter >= 0 && label_counter <= 7 ?
3516 MICROLABEL_LEVEL_NAME :
3517 label_counter >= 9 && label_counter <= 12 ?
3518 MICROLABEL_LEVEL_AUTHOR_HEAD :
3519 label_counter >= 14 && label_counter <= 21 ?
3520 MICROLABEL_LEVEL_AUTHOR :
3521 label_counter >= 23 && label_counter <= 26 ?
3522 MICROLABEL_IMPORTED_FROM_HEAD :
3523 label_counter >= 28 && label_counter <= 35 ?
3524 MICROLABEL_IMPORTED_FROM :
3525 label_counter >= 37 && label_counter <= 40 ?
3526 MICROLABEL_IMPORTED_BY_HEAD :
3527 label_counter >= 42 && label_counter <= 49 ?
3528 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
3530 if (leveldir_current->imported_from == NULL &&
3531 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
3532 label_state == MICROLABEL_IMPORTED_FROM))
3533 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
3534 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
3536 DrawPreviewLevelLabelExt(label_state);
3539 game_status = last_game_status; /* restore current game status */
3542 void DrawPreviewLevelInitial()
3544 DrawPreviewLevelExt(TRUE);
3547 void DrawPreviewLevelAnimation()
3549 DrawPreviewLevelExt(FALSE);
3552 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3553 int graphic, int sync_frame, int mask_mode)
3555 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3557 if (mask_mode == USE_MASKING)
3558 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3560 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
3563 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
3564 int graphic, int sync_frame,
3567 int frame = getGraphicAnimationFrame(graphic, sync_frame);
3569 if (mask_mode == USE_MASKING)
3570 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
3572 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
3575 inline void DrawGraphicAnimation(int x, int y, int graphic)
3577 int lx = LEVELX(x), ly = LEVELY(y);
3579 if (!IN_SCR_FIELD(x, y))
3583 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
3584 graphic, GfxFrame[lx][ly], NO_MASKING);
3586 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3587 graphic, GfxFrame[lx][ly], NO_MASKING);
3589 MarkTileDirty(x, y);
3592 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
3594 int lx = LEVELX(x), ly = LEVELY(y);
3596 if (!IN_SCR_FIELD(x, y))
3599 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
3600 graphic, GfxFrame[lx][ly], NO_MASKING);
3601 MarkTileDirty(x, y);
3604 void DrawLevelGraphicAnimation(int x, int y, int graphic)
3606 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3609 void DrawLevelElementAnimation(int x, int y, int element)
3611 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3613 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
3616 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
3618 int sx = SCREENX(x), sy = SCREENY(y);
3620 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3623 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3626 DrawGraphicAnimation(sx, sy, graphic);
3629 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
3630 DrawLevelFieldCrumbled(x, y);
3632 if (GFX_CRUMBLED(Feld[x][y]))
3633 DrawLevelFieldCrumbled(x, y);
3637 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
3639 int sx = SCREENX(x), sy = SCREENY(y);
3642 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
3645 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
3647 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
3650 DrawGraphicAnimation(sx, sy, graphic);
3652 if (GFX_CRUMBLED(element))
3653 DrawLevelFieldCrumbled(x, y);
3656 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
3658 if (player->use_murphy)
3660 /* this works only because currently only one player can be "murphy" ... */
3661 static int last_horizontal_dir = MV_LEFT;
3662 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
3664 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3665 last_horizontal_dir = move_dir;
3667 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
3669 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
3671 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
3677 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
3680 static boolean equalGraphics(int graphic1, int graphic2)
3682 struct GraphicInfo *g1 = &graphic_info[graphic1];
3683 struct GraphicInfo *g2 = &graphic_info[graphic2];
3685 return (g1->bitmap == g2->bitmap &&
3686 g1->src_x == g2->src_x &&
3687 g1->src_y == g2->src_y &&
3688 g1->anim_frames == g2->anim_frames &&
3689 g1->anim_delay == g2->anim_delay &&
3690 g1->anim_mode == g2->anim_mode);
3693 void DrawAllPlayers()
3697 for (i = 0; i < MAX_PLAYERS; i++)
3698 if (stored_player[i].active)
3699 DrawPlayer(&stored_player[i]);
3702 void DrawPlayerField(int x, int y)
3704 if (!IS_PLAYER(x, y))
3707 DrawPlayer(PLAYERINFO(x, y));
3710 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
3712 void DrawPlayer(struct PlayerInfo *player)
3714 int jx = player->jx;
3715 int jy = player->jy;
3716 int move_dir = player->MovDir;
3717 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
3718 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
3719 int last_jx = (player->is_moving ? jx - dx : jx);
3720 int last_jy = (player->is_moving ? jy - dy : jy);
3721 int next_jx = jx + dx;
3722 int next_jy = jy + dy;
3723 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
3724 boolean player_is_opaque = FALSE;
3725 int sx = SCREENX(jx), sy = SCREENY(jy);
3726 int sxx = 0, syy = 0;
3727 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
3729 int action = ACTION_DEFAULT;
3730 int last_player_graphic = getPlayerGraphic(player, move_dir);
3731 int last_player_frame = player->Frame;
3734 /* GfxElement[][] is set to the element the player is digging or collecting;
3735 remove also for off-screen player if the player is not moving anymore */
3736 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
3737 GfxElement[jx][jy] = EL_UNDEFINED;
3739 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
3743 if (!IN_LEV_FIELD(jx, jy))
3745 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
3746 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
3747 printf("DrawPlayerField(): This should never happen!\n");
3752 if (element == EL_EXPLOSION)
3755 action = (player->is_pushing ? ACTION_PUSHING :
3756 player->is_digging ? ACTION_DIGGING :
3757 player->is_collecting ? ACTION_COLLECTING :
3758 player->is_moving ? ACTION_MOVING :
3759 player->is_snapping ? ACTION_SNAPPING :
3760 player->is_dropping ? ACTION_DROPPING :
3761 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
3763 if (player->is_waiting)
3764 move_dir = player->dir_waiting;
3766 InitPlayerGfxAnimation(player, action, move_dir);
3768 /* ----------------------------------------------------------------------- */
3769 /* draw things in the field the player is leaving, if needed */
3770 /* ----------------------------------------------------------------------- */
3772 if (player->is_moving)
3774 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
3776 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
3778 if (last_element == EL_DYNAMITE_ACTIVE ||
3779 last_element == EL_EM_DYNAMITE_ACTIVE ||
3780 last_element == EL_SP_DISK_RED_ACTIVE)
3781 DrawDynamite(last_jx, last_jy);
3783 DrawLevelFieldThruMask(last_jx, last_jy);
3785 else if (last_element == EL_DYNAMITE_ACTIVE ||
3786 last_element == EL_EM_DYNAMITE_ACTIVE ||
3787 last_element == EL_SP_DISK_RED_ACTIVE)
3788 DrawDynamite(last_jx, last_jy);
3790 /* !!! this is not enough to prevent flickering of players which are
3791 moving next to each others without a free tile between them -- this
3792 can only be solved by drawing all players layer by layer (first the
3793 background, then the foreground etc.) !!! => TODO */
3794 else if (!IS_PLAYER(last_jx, last_jy))
3795 DrawLevelField(last_jx, last_jy);
3798 DrawLevelField(last_jx, last_jy);
3801 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
3802 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3805 if (!IN_SCR_FIELD(sx, sy))
3808 /* ----------------------------------------------------------------------- */
3809 /* draw things behind the player, if needed */
3810 /* ----------------------------------------------------------------------- */
3813 DrawLevelElement(jx, jy, Back[jx][jy]);
3814 else if (IS_ACTIVE_BOMB(element))
3815 DrawLevelElement(jx, jy, EL_EMPTY);
3818 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3820 int old_element = GfxElement[jx][jy];
3821 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3822 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3824 if (GFX_CRUMBLED(old_element))
3825 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3827 DrawGraphic(sx, sy, old_graphic, frame);
3829 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3830 player_is_opaque = TRUE;
3834 GfxElement[jx][jy] = EL_UNDEFINED;
3836 /* make sure that pushed elements are drawn with correct frame rate */
3838 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3840 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3841 GfxFrame[jx][jy] = player->StepFrame;
3843 if (player->is_pushing && player->is_moving)
3844 GfxFrame[jx][jy] = player->StepFrame;
3847 DrawLevelField(jx, jy);
3851 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3852 /* ----------------------------------------------------------------------- */
3853 /* draw player himself */
3854 /* ----------------------------------------------------------------------- */
3856 graphic = getPlayerGraphic(player, move_dir);
3858 /* in the case of changed player action or direction, prevent the current
3859 animation frame from being restarted for identical animations */
3860 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3861 player->Frame = last_player_frame;
3863 frame = getGraphicAnimationFrame(graphic, player->Frame);
3867 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3868 sxx = player->GfxPos;
3870 syy = player->GfxPos;
3873 if (!setup.soft_scrolling && ScreenMovPos)
3876 if (player_is_opaque)
3877 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3879 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3881 if (SHIELD_ON(player))
3883 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3884 IMG_SHIELD_NORMAL_ACTIVE);
3885 int frame = getGraphicAnimationFrame(graphic, -1);
3887 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3891 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3894 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3895 sxx = player->GfxPos;
3897 syy = player->GfxPos;
3901 /* ----------------------------------------------------------------------- */
3902 /* draw things the player is pushing, if needed */
3903 /* ----------------------------------------------------------------------- */
3906 printf("::: %d, %d [%d, %d] [%d]\n",
3907 player->is_pushing, player_is_moving, player->GfxAction,
3908 player->is_moving, player_is_moving);
3912 if (player->is_pushing && player->is_moving)
3914 int px = SCREENX(jx), py = SCREENY(jy);
3915 int pxx = (TILEX - ABS(sxx)) * dx;
3916 int pyy = (TILEY - ABS(syy)) * dy;
3917 int gfx_frame = GfxFrame[jx][jy];
3923 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3925 element = Feld[next_jx][next_jy];
3926 gfx_frame = GfxFrame[next_jx][next_jy];
3929 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3932 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3933 frame = getGraphicAnimationFrame(graphic, sync_frame);
3935 frame = getGraphicAnimationFrame(graphic, player->StepFrame);
3938 /* draw background element under pushed element (like the Sokoban field) */
3940 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3942 /* this allows transparent pushing animation over non-black background */
3945 DrawLevelElement(jx, jy, Back[jx][jy]);
3947 DrawLevelElement(jx, jy, EL_EMPTY);
3949 if (Back[next_jx][next_jy])
3950 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3952 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3954 else if (Back[next_jx][next_jy])
3955 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3957 if (Back[next_jx][next_jy])
3958 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3962 printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
3963 jx, px, player->GfxPos, player->StepFrame,
3968 GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
3972 /* do not draw (EM style) pushing animation when pushing is finished */
3973 /* (two-tile animations usually do not contain start and end frame) */
3974 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3975 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3977 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3979 /* masked drawing is needed for EMC style (double) movement graphics */
3980 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3981 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3986 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3987 /* ----------------------------------------------------------------------- */
3988 /* draw player himself */
3989 /* ----------------------------------------------------------------------- */
3991 graphic = getPlayerGraphic(player, move_dir);
3993 /* in the case of changed player action or direction, prevent the current
3994 animation frame from being restarted for identical animations */
3995 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3996 player->Frame = last_player_frame;
3998 frame = getGraphicAnimationFrame(graphic, player->Frame);
4002 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
4003 sxx = player->GfxPos;
4005 syy = player->GfxPos;
4008 if (!setup.soft_scrolling && ScreenMovPos)
4011 if (player_is_opaque)
4012 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
4014 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4016 if (SHIELD_ON(player))
4018 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
4019 IMG_SHIELD_NORMAL_ACTIVE);
4020 int frame = getGraphicAnimationFrame(graphic, -1);
4022 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
4026 /* ----------------------------------------------------------------------- */
4027 /* draw things in front of player (active dynamite or dynabombs) */
4028 /* ----------------------------------------------------------------------- */
4030 if (IS_ACTIVE_BOMB(element))
4032 graphic = el2img(element);
4033 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
4035 if (game.emulation == EMU_SUPAPLEX)
4036 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
4038 DrawGraphicThruMask(sx, sy, graphic, frame);
4041 if (player_is_moving && last_element == EL_EXPLOSION)
4043 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
4044 GfxElement[last_jx][last_jy] : EL_EMPTY);
4045 int graphic = el_act2img(element, ACTION_EXPLODING);
4046 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
4047 int phase = ExplodePhase[last_jx][last_jy] - 1;
4048 int frame = getGraphicAnimationFrame(graphic, phase - delay);
4051 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
4054 /* ----------------------------------------------------------------------- */
4055 /* draw elements the player is just walking/passing through/under */
4056 /* ----------------------------------------------------------------------- */
4058 if (player_is_moving)
4060 /* handle the field the player is leaving ... */
4061 if (IS_ACCESSIBLE_INSIDE(last_element))
4062 DrawLevelField(last_jx, last_jy);
4063 else if (IS_ACCESSIBLE_UNDER(last_element))
4064 DrawLevelFieldThruMask(last_jx, last_jy);
4067 /* do not redraw accessible elements if the player is just pushing them */
4068 if (!player_is_moving || !player->is_pushing)
4070 /* ... and the field the player is entering */
4071 if (IS_ACCESSIBLE_INSIDE(element))
4072 DrawLevelField(jx, jy);
4073 else if (IS_ACCESSIBLE_UNDER(element))
4074 DrawLevelFieldThruMask(jx, jy);
4077 MarkTileDirty(sx, sy);
4080 /* ------------------------------------------------------------------------- */
4082 void WaitForEventToContinue()
4084 boolean still_wait = TRUE;
4086 /* simulate releasing mouse button over last gadget, if still pressed */
4088 HandleGadgets(-1, -1, 0);
4090 button_status = MB_RELEASED;
4106 case EVENT_BUTTONPRESS:
4107 case EVENT_KEYPRESS:
4111 case EVENT_KEYRELEASE:
4112 ClearPlayerAction();
4116 HandleOtherEvents(&event);
4120 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4127 /* don't eat all CPU time */
4132 #define MAX_REQUEST_LINES 13
4133 #define MAX_REQUEST_LINE_FONT1_LEN 7
4134 #define MAX_REQUEST_LINE_FONT2_LEN 10
4138 static int RequestHandleEvents(unsigned int req_state)
4140 int last_game_status = game_status; /* save current game status */
4144 button_status = MB_RELEASED;
4146 request_gadget_id = -1;
4159 case EVENT_BUTTONPRESS:
4160 case EVENT_BUTTONRELEASE:
4161 case EVENT_MOTIONNOTIFY:
4163 if (event.type == EVENT_MOTIONNOTIFY)
4165 if (!PointerInWindow(window))
4166 continue; /* window and pointer are on different screens */
4171 motion_status = TRUE;
4172 mx = ((MotionEvent *) &event)->x;
4173 my = ((MotionEvent *) &event)->y;
4177 motion_status = FALSE;
4178 mx = ((ButtonEvent *) &event)->x;
4179 my = ((ButtonEvent *) &event)->y;
4180 if (event.type == EVENT_BUTTONPRESS)
4181 button_status = ((ButtonEvent *) &event)->button;
4183 button_status = MB_RELEASED;
4186 /* this sets 'request_gadget_id' */
4187 HandleGadgets(mx, my, button_status);
4189 switch (request_gadget_id)
4191 case TOOL_CTRL_ID_YES:
4194 case TOOL_CTRL_ID_NO:
4197 case TOOL_CTRL_ID_CONFIRM:
4198 result = TRUE | FALSE;
4201 case TOOL_CTRL_ID_PLAYER_1:
4204 case TOOL_CTRL_ID_PLAYER_2:
4207 case TOOL_CTRL_ID_PLAYER_3:
4210 case TOOL_CTRL_ID_PLAYER_4:
4221 case EVENT_KEYPRESS:
4222 switch (GetEventKey((KeyEvent *)&event, TRUE))
4225 if (req_state & REQ_CONFIRM)
4234 #if defined(TARGET_SDL2)
4244 if (req_state & REQ_PLAYER)
4248 case EVENT_KEYRELEASE:
4249 ClearPlayerAction();
4253 HandleOtherEvents(&event);
4257 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
4259 int joy = AnyJoystick();
4261 if (joy & JOY_BUTTON_1)
4263 else if (joy & JOY_BUTTON_2)
4269 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
4271 HandleGameActions();
4277 if (!PendingEvent()) /* delay only if no pending events */
4282 game_status = GAME_MODE_PSEUDO_DOOR;
4288 game_status = last_game_status; /* restore current game status */
4296 if (!PendingEvent()) /* delay only if no pending events */
4299 /* don't eat all CPU time */
4309 static boolean RequestDoor(char *text, unsigned int req_state)
4311 unsigned int old_door_state;
4312 int last_game_status = game_status; /* save current game status */
4313 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4314 int font_nr = FONT_TEXT_2;
4319 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4321 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4322 font_nr = FONT_TEXT_1;
4325 if (game_status == GAME_MODE_PLAYING)
4327 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4328 BlitScreenToBitmap_EM(backbuffer);
4329 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4330 BlitScreenToBitmap_SP(backbuffer);
4333 /* disable deactivated drawing when quick-loading level tape recording */
4334 if (tape.playing && tape.deactivate_display)
4335 TapeDeactivateDisplayOff(TRUE);
4337 SetMouseCursor(CURSOR_DEFAULT);
4339 #if defined(NETWORK_AVALIABLE)
4340 /* pause network game while waiting for request to answer */
4341 if (options.network &&
4342 game_status == GAME_MODE_PLAYING &&
4343 req_state & REQUEST_WAIT_FOR_INPUT)
4344 SendToServer_PausePlaying();
4347 old_door_state = GetDoorState();
4349 /* simulate releasing mouse button over last gadget, if still pressed */
4351 HandleGadgets(-1, -1, 0);
4355 /* draw released gadget before proceeding */
4358 if (old_door_state & DOOR_OPEN_1)
4360 CloseDoor(DOOR_CLOSE_1);
4362 /* save old door content */
4363 BlitBitmap(bitmap_db_door, bitmap_db_door,
4364 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4365 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4368 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4369 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4371 /* clear door drawing field */
4372 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4374 /* force DOOR font inside door area */
4375 game_status = GAME_MODE_PSEUDO_DOOR;
4377 /* write text for request */
4378 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4380 char text_line[max_request_line_len + 1];
4386 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4388 tc = *(text_ptr + tx);
4389 if (!tc || tc == ' ')
4400 strncpy(text_line, text_ptr, tl);
4403 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4404 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4405 text_line, font_nr);
4407 text_ptr += tl + (tc == ' ' ? 1 : 0);
4410 game_status = last_game_status; /* restore current game status */
4412 if (req_state & REQ_ASK)
4414 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4415 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4417 else if (req_state & REQ_CONFIRM)
4419 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4421 else if (req_state & REQ_PLAYER)
4423 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4424 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4425 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4426 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4429 /* copy request gadgets to door backbuffer */
4430 BlitBitmap(drawto, bitmap_db_door,
4431 DX, DY, DXSIZE, DYSIZE,
4432 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4434 OpenDoor(DOOR_OPEN_1);
4436 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4438 if (game_status == GAME_MODE_PLAYING)
4440 SetPanelBackground();
4441 SetDrawBackgroundMask(REDRAW_DOOR_1);
4445 SetDrawBackgroundMask(REDRAW_FIELD);
4451 if (game_status != GAME_MODE_MAIN)
4454 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4456 // ---------- handle request buttons ----------
4457 result = RequestHandleEvents(req_state);
4459 if (game_status != GAME_MODE_MAIN)
4464 if (!(req_state & REQ_STAY_OPEN))
4466 CloseDoor(DOOR_CLOSE_1);
4468 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
4469 (req_state & REQ_REOPEN))
4470 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4475 if (game_status == GAME_MODE_PLAYING)
4477 SetPanelBackground();
4478 SetDrawBackgroundMask(REDRAW_DOOR_1);
4482 SetDrawBackgroundMask(REDRAW_FIELD);
4485 #if defined(NETWORK_AVALIABLE)
4486 /* continue network game after request */
4487 if (options.network &&
4488 game_status == GAME_MODE_PLAYING &&
4489 req_state & REQUEST_WAIT_FOR_INPUT)
4490 SendToServer_ContinuePlaying();
4493 /* restore deactivated drawing when quick-loading level tape recording */
4494 if (tape.playing && tape.deactivate_display)
4495 TapeDeactivateDisplayOn();
4500 static boolean RequestEnvelope(char *text, unsigned int req_state)
4507 if (game_status == GAME_MODE_PLAYING)
4509 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4510 BlitScreenToBitmap_EM(backbuffer);
4511 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4512 BlitScreenToBitmap_SP(backbuffer);
4515 /* disable deactivated drawing when quick-loading level tape recording */
4516 if (tape.playing && tape.deactivate_display)
4517 TapeDeactivateDisplayOff(TRUE);
4519 SetMouseCursor(CURSOR_DEFAULT);
4521 #if defined(NETWORK_AVALIABLE)
4522 /* pause network game while waiting for request to answer */
4523 if (options.network &&
4524 game_status == GAME_MODE_PLAYING &&
4525 req_state & REQUEST_WAIT_FOR_INPUT)
4526 SendToServer_PausePlaying();
4529 /* simulate releasing mouse button over last gadget, if still pressed */
4531 HandleGadgets(-1, -1, 0);
4535 // (replace with setting corresponding request background)
4536 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4537 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4539 /* clear door drawing field */
4540 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
4543 if (global.use_envelope_request)
4547 CreateToolButtons();
4553 if (req_state & REQ_ASK)
4555 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_YES], FALSE);
4556 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_NO], FALSE);
4558 else if (req_state & REQ_CONFIRM)
4560 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_CONFIRM], FALSE);
4562 else if (req_state & REQ_PLAYER)
4564 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_1], FALSE);
4565 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_2], FALSE);
4566 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_3], FALSE);
4567 MapGadgetExt(tool_gadget[TOOL_CTRL_ID_PLAYER_4], FALSE);
4570 if (req_state & REQ_ASK)
4572 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4573 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4575 else if (req_state & REQ_CONFIRM)
4577 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4579 else if (req_state & REQ_PLAYER)
4581 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4582 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4583 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4584 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4589 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
4592 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4594 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4595 i == TOOL_CTRL_ID_NO)) ||
4596 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4597 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4598 i == TOOL_CTRL_ID_PLAYER_2 &&
4599 i == TOOL_CTRL_ID_PLAYER_3 &&
4600 i == TOOL_CTRL_ID_PLAYER_4)))
4602 int x = tool_gadget[i]->x + dDX;
4603 int y = tool_gadget[i]->y + dDY;
4605 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4610 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4612 if (game_status == GAME_MODE_PLAYING)
4614 SetPanelBackground();
4615 SetDrawBackgroundMask(REDRAW_DOOR_1);
4619 SetDrawBackgroundMask(REDRAW_FIELD);
4626 if (game_status != GAME_MODE_MAIN)
4630 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4632 // ---------- handle request buttons ----------
4633 result = RequestHandleEvents(req_state);
4635 if (game_status != GAME_MODE_MAIN)
4640 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
4644 if (game_status == GAME_MODE_PLAYING)
4646 SetPanelBackground();
4647 SetDrawBackgroundMask(REDRAW_DOOR_1);
4651 SetDrawBackgroundMask(REDRAW_FIELD);
4654 #if defined(NETWORK_AVALIABLE)
4655 /* continue network game after request */
4656 if (options.network &&
4657 game_status == GAME_MODE_PLAYING &&
4658 req_state & REQUEST_WAIT_FOR_INPUT)
4659 SendToServer_ContinuePlaying();
4662 /* restore deactivated drawing when quick-loading level tape recording */
4663 if (tape.playing && tape.deactivate_display)
4664 TapeDeactivateDisplayOn();
4669 boolean Request(char *text, unsigned int req_state)
4671 if (global.use_envelope_request)
4672 return RequestEnvelope(text, req_state);
4674 return RequestDoor(text, req_state);
4677 #else // =====================================================================
4679 boolean Request(char *text, unsigned int req_state)
4681 int mx, my, ty, result = -1;
4682 unsigned int old_door_state;
4683 int last_game_status = game_status; /* save current game status */
4684 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
4685 int font_nr = FONT_TEXT_2;
4687 int max_word_len = 0;
4693 global.use_envelope_request = 1;
4697 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
4699 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4700 font_nr = FONT_TEXT_1;
4703 for (text_ptr = text; *text_ptr; text_ptr++)
4705 max_word_len = (*text_ptr != ' ' ? max_word_len + 1 : 0);
4707 if (max_word_len > MAX_REQUEST_LINE_FONT1_LEN)
4709 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
4711 font_nr = FONT_TEXT_1;
4713 font_nr = FONT_LEVEL_NUMBER;
4721 if (game_status == GAME_MODE_PLAYING)
4723 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
4724 BlitScreenToBitmap_EM(backbuffer);
4725 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
4726 BlitScreenToBitmap_SP(backbuffer);
4729 /* disable deactivated drawing when quick-loading level tape recording */
4730 if (tape.playing && tape.deactivate_display)
4731 TapeDeactivateDisplayOff(TRUE);
4733 SetMouseCursor(CURSOR_DEFAULT);
4735 #if defined(NETWORK_AVALIABLE)
4736 /* pause network game while waiting for request to answer */
4737 if (options.network &&
4738 game_status == GAME_MODE_PLAYING &&
4739 req_state & REQUEST_WAIT_FOR_INPUT)
4740 SendToServer_PausePlaying();
4743 old_door_state = GetDoorState();
4745 /* simulate releasing mouse button over last gadget, if still pressed */
4747 HandleGadgets(-1, -1, 0);
4751 /* draw released gadget before proceeding */
4755 if (old_door_state & DOOR_OPEN_1 && !global.use_envelope_request)
4757 if (old_door_state & DOOR_OPEN_1)
4761 if (!global.use_envelope_request)
4762 CloseDoor(DOOR_CLOSE_1);
4764 CloseDoor(DOOR_CLOSE_1);
4767 /* save old door content */
4768 BlitBitmap(bitmap_db_door, bitmap_db_door,
4769 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
4770 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
4774 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
4777 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4779 /* clear door drawing field */
4780 DrawBackground(DX, DY, DXSIZE, DYSIZE);
4782 /* force DOOR font inside door area */
4783 game_status = GAME_MODE_PSEUDO_DOOR;
4785 /* write text for request */
4786 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
4788 char text_line[max_request_line_len + 1];
4794 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
4796 tc = *(text_ptr + tx);
4797 if (!tc || tc == ' ')
4808 strncpy(text_line, text_ptr, tl);
4811 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
4812 DY + 8 + ty * (getFontHeight(font_nr) + 2),
4813 text_line, font_nr);
4815 text_ptr += tl + (tc == ' ' ? 1 : 0);
4818 game_status = last_game_status; /* restore current game status */
4821 if (global.use_envelope_request)
4825 CreateToolButtons();
4829 if (req_state & REQ_ASK)
4831 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
4832 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
4834 else if (req_state & REQ_CONFIRM)
4836 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
4838 else if (req_state & REQ_PLAYER)
4840 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
4841 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
4842 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
4843 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
4846 /* copy request gadgets to door backbuffer */
4847 BlitBitmap(drawto, bitmap_db_door,
4848 DX, DY, DXSIZE, DYSIZE,
4849 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
4852 if (global.use_envelope_request)
4854 ShowEnvelopeRequest(text, ACTION_OPENING);
4856 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4858 if ((req_state & REQ_ASK && (i == TOOL_CTRL_ID_YES ||
4859 i == TOOL_CTRL_ID_NO)) ||
4860 (req_state & REQ_CONFIRM && i == TOOL_CTRL_ID_CONFIRM) ||
4861 (req_state & REQ_PLAYER && (i == TOOL_CTRL_ID_PLAYER_1 &&
4862 i == TOOL_CTRL_ID_PLAYER_2 &&
4863 i == TOOL_CTRL_ID_PLAYER_3 &&
4864 i == TOOL_CTRL_ID_PLAYER_4)))
4866 int x = tool_gadget[i]->x + dDX;
4867 int y = tool_gadget[i]->y + dDY;
4869 ModifyGadget(tool_gadget[i], GDI_X, x, GDI_Y, y, GDI_END);
4876 if (!global.use_envelope_request)
4877 OpenDoor(DOOR_OPEN_1);
4879 OpenDoor(DOOR_OPEN_1);
4882 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
4884 if (game_status == GAME_MODE_PLAYING)
4886 SetPanelBackground();
4887 SetDrawBackgroundMask(REDRAW_DOOR_1);
4891 SetDrawBackgroundMask(REDRAW_FIELD);
4898 if (game_status != GAME_MODE_MAIN && !global.use_envelope_request)
4901 if (game_status != GAME_MODE_MAIN)
4905 button_status = MB_RELEASED;
4907 request_gadget_id = -1;
4909 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
4921 case EVENT_BUTTONPRESS:
4922 case EVENT_BUTTONRELEASE:
4923 case EVENT_MOTIONNOTIFY:
4925 if (event.type == EVENT_MOTIONNOTIFY)
4927 if (!PointerInWindow(window))
4928 continue; /* window and pointer are on different screens */
4933 motion_status = TRUE;
4934 mx = ((MotionEvent *) &event)->x;
4935 my = ((MotionEvent *) &event)->y;
4939 motion_status = FALSE;
4940 mx = ((ButtonEvent *) &event)->x;
4941 my = ((ButtonEvent *) &event)->y;
4942 if (event.type == EVENT_BUTTONPRESS)
4943 button_status = ((ButtonEvent *) &event)->button;
4945 button_status = MB_RELEASED;
4948 /* this sets 'request_gadget_id' */
4949 HandleGadgets(mx, my, button_status);
4951 switch (request_gadget_id)
4953 case TOOL_CTRL_ID_YES:
4956 case TOOL_CTRL_ID_NO:
4959 case TOOL_CTRL_ID_CONFIRM:
4960 result = TRUE | FALSE;
4963 case TOOL_CTRL_ID_PLAYER_1:
4966 case TOOL_CTRL_ID_PLAYER_2:
4969 case TOOL_CTRL_ID_PLAYER_3:
4972 case TOOL_CTRL_ID_PLAYER_4:
4983 case EVENT_KEYPRESS:
4984 switch (GetEventKey((KeyEvent *)&event, TRUE))
4987 if (req_state & REQ_CONFIRM)
4996 #if defined(TARGET_SDL2)
5006 if (req_state & REQ_PLAYER)
5010 case EVENT_KEYRELEASE:
5011 ClearPlayerAction();
5015 HandleOtherEvents(&event);
5019 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
5021 int joy = AnyJoystick();
5023 if (joy & JOY_BUTTON_1)
5025 else if (joy & JOY_BUTTON_2)
5031 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
5033 HandleGameActions();
5039 if (!PendingEvent()) /* delay only if no pending events */
5044 game_status = GAME_MODE_PSEUDO_DOOR;
5050 game_status = last_game_status; /* restore current game status */
5058 if (!PendingEvent()) /* delay only if no pending events */
5061 /* don't eat all CPU time */
5068 if (game_status != GAME_MODE_MAIN)
5074 if (global.use_envelope_request)
5075 ShowEnvelopeRequest(text, ACTION_CLOSING);
5079 if (!(req_state & REQ_STAY_OPEN) && !global.use_envelope_request)
5081 if (!(req_state & REQ_STAY_OPEN))
5084 CloseDoor(DOOR_CLOSE_1);
5086 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
5087 (req_state & REQ_REOPEN))
5088 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
5093 if (game_status == GAME_MODE_PLAYING)
5095 SetPanelBackground();
5096 SetDrawBackgroundMask(REDRAW_DOOR_1);
5100 SetDrawBackgroundMask(REDRAW_FIELD);
5103 #if defined(NETWORK_AVALIABLE)
5104 /* continue network game after request */
5105 if (options.network &&
5106 game_status == GAME_MODE_PLAYING &&
5107 req_state & REQUEST_WAIT_FOR_INPUT)
5108 SendToServer_ContinuePlaying();
5111 /* restore deactivated drawing when quick-loading level tape recording */
5112 if (tape.playing && tape.deactivate_display)
5113 TapeDeactivateDisplayOn();
5120 unsigned int OpenDoor(unsigned int door_state)
5122 if (door_state & DOOR_COPY_BACK)
5124 if (door_state & DOOR_OPEN_1)
5125 BlitBitmap(bitmap_db_door, bitmap_db_door,
5126 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
5127 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5129 if (door_state & DOOR_OPEN_2)
5130 BlitBitmap(bitmap_db_door, bitmap_db_door,
5131 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY2, VXSIZE, VYSIZE,
5132 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5134 door_state &= ~DOOR_COPY_BACK;
5137 return MoveDoor(door_state);
5140 unsigned int CloseDoor(unsigned int door_state)
5142 unsigned int old_door_state = GetDoorState();
5144 if (!(door_state & DOOR_NO_COPY_BACK))
5146 if (old_door_state & DOOR_OPEN_1)
5147 BlitBitmap(backbuffer, bitmap_db_door,
5148 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
5150 if (old_door_state & DOOR_OPEN_2)
5151 BlitBitmap(backbuffer, bitmap_db_door,
5152 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
5154 door_state &= ~DOOR_NO_COPY_BACK;
5157 return MoveDoor(door_state);
5160 unsigned int GetDoorState()
5162 return MoveDoor(DOOR_GET_STATE);
5165 unsigned int SetDoorState(unsigned int door_state)
5167 return MoveDoor(door_state | DOOR_SET_STATE);
5170 unsigned int MoveDoor(unsigned int door_state)
5172 static int door1 = DOOR_OPEN_1;
5173 static int door2 = DOOR_CLOSE_2;
5174 unsigned int door_delay = 0;
5175 unsigned int door_delay_value;
5178 if (door_1.width < 0 || door_1.width > DXSIZE)
5179 door_1.width = DXSIZE;
5180 if (door_1.height < 0 || door_1.height > DYSIZE)
5181 door_1.height = DYSIZE;
5182 if (door_2.width < 0 || door_2.width > VXSIZE)
5183 door_2.width = VXSIZE;
5184 if (door_2.height < 0 || door_2.height > VYSIZE)
5185 door_2.height = VYSIZE;
5187 if (door_state == DOOR_GET_STATE)
5188 return (door1 | door2);
5190 if (door_state & DOOR_SET_STATE)
5192 if (door_state & DOOR_ACTION_1)
5193 door1 = door_state & DOOR_ACTION_1;
5194 if (door_state & DOOR_ACTION_2)
5195 door2 = door_state & DOOR_ACTION_2;
5197 return (door1 | door2);
5200 if (!(door_state & DOOR_FORCE_REDRAW))
5202 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
5203 door_state &= ~DOOR_OPEN_1;
5204 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
5205 door_state &= ~DOOR_CLOSE_1;
5206 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
5207 door_state &= ~DOOR_OPEN_2;
5208 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
5209 door_state &= ~DOOR_CLOSE_2;
5212 door_delay_value = (door_state & DOOR_ACTION_1 ? door_1.step_delay :
5215 if (setup.quick_doors)
5217 stepsize = 20; /* must be chosen to always draw last frame */
5218 door_delay_value = 0;
5221 if (global.autoplay_leveldir)
5223 door_state |= DOOR_NO_DELAY;
5224 door_state &= ~DOOR_CLOSE_ALL;
5228 if (game_status == GAME_MODE_EDITOR)
5229 door_state |= DOOR_NO_DELAY;
5232 if (door_state & DOOR_ACTION)
5234 boolean handle_door_1 = (door_state & DOOR_ACTION_1);
5235 boolean handle_door_2 = (door_state & DOOR_ACTION_2);
5236 boolean door_1_done = (!handle_door_1);
5237 boolean door_2_done = (!handle_door_2);
5238 boolean door_1_vertical = (door_1.anim_mode & ANIM_VERTICAL);
5239 boolean door_2_vertical = (door_2.anim_mode & ANIM_VERTICAL);
5240 int door_size_1 = (door_1_vertical ? door_1.height : door_1.width);
5241 int door_size_2 = (door_2_vertical ? door_2.height : door_2.width);
5242 int max_door_size_1 = (door_1_vertical ? DYSIZE : DXSIZE);
5243 int max_door_size_2 = (door_2_vertical ? VYSIZE : VXSIZE);
5244 int door_size = (handle_door_1 ? door_size_1 : door_size_2);
5245 int max_door_size = (handle_door_1 ? max_door_size_1 : max_door_size_2);
5246 int door_skip = max_door_size - door_size;
5247 int end = door_size;
5248 int start = ((door_state & DOOR_NO_DELAY) ? end : 0);
5251 if (!(door_state & DOOR_NO_DELAY) && !setup.quick_doors)
5253 /* opening door sound has priority over simultaneously closing door */
5254 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
5255 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
5256 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
5257 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
5260 for (k = start; k <= end && !(door_1_done && door_2_done); k += stepsize)
5263 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5264 GC gc = bitmap->stored_clip_gc;
5266 if (door_state & DOOR_ACTION_1)
5268 int a = MIN(x * door_1.step_offset, end);
5269 int p = (door_state & DOOR_OPEN_1 ? end - a : a);
5270 int i = p + door_skip;
5272 if (door_1.anim_mode & ANIM_STATIC_PANEL)
5274 BlitBitmap(bitmap_db_door, drawto,
5275 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1,
5276 DXSIZE, DYSIZE, DX, DY);
5280 BlitBitmap(bitmap_db_door, drawto,
5281 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + p / 2,
5282 DXSIZE, DYSIZE - p / 2, DX, DY);
5284 ClearRectangle(drawto, DX, DY + DYSIZE - p / 2, DXSIZE, p / 2);
5287 if (door_1.anim_mode & ANIM_HORIZONTAL && x <= DXSIZE)
5289 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5290 int dst1_x = DX + DXSIZE - i, dst1_y = DY;
5291 int src2_x = DXSIZE - i, src2_y = DOOR_GFX_PAGEY1;
5292 int dst2_x = DX, dst2_y = DY;
5293 int width = i, height = DYSIZE;
5295 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5296 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5299 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5300 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5303 else if (door_1.anim_mode & ANIM_VERTICAL && x <= DYSIZE)
5305 int src1_x = DXSIZE, src1_y = DOOR_GFX_PAGEY1;
5306 int dst1_x = DX, dst1_y = DY + DYSIZE - i;
5307 int src2_x = 0, src2_y = DOOR_GFX_PAGEY1 + DYSIZE - i;
5308 int dst2_x = DX, dst2_y = DY;
5309 int width = DXSIZE, height = i;
5311 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5312 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5315 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5316 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5319 else if (x <= DXSIZE) /* ANIM_DEFAULT */
5321 int j = (door_1.anim_mode == ANIM_DEFAULT ? (DXSIZE - i) / 3 : 0);
5323 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
5324 BlitBitmapMasked(bitmap, drawto,
5325 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
5326 DX + DXSIZE - i, DY + j);
5327 BlitBitmapMasked(bitmap, drawto,
5328 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
5329 DX + DXSIZE - i, DY + 140 + j);
5330 SetClipOrigin(bitmap, gc, DX - DXSIZE + i,
5331 DY - (DOOR_GFX_PAGEY1 + j));
5332 BlitBitmapMasked(bitmap, drawto,
5333 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
5335 BlitBitmapMasked(bitmap, drawto,
5336 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
5339 BlitBitmapMasked(bitmap, drawto,
5340 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
5342 BlitBitmapMasked(bitmap, drawto,
5343 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
5345 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
5346 BlitBitmapMasked(bitmap, drawto,
5347 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
5348 DX + DXSIZE - i, DY + 77 + j);
5349 BlitBitmapMasked(bitmap, drawto,
5350 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
5351 DX + DXSIZE - i, DY + 203 + j);
5354 redraw_mask |= REDRAW_DOOR_1;
5355 door_1_done = (a == end);
5358 if (door_state & DOOR_ACTION_2)
5360 int a = MIN(x * door_2.step_offset, door_size);
5361 int p = (door_state & DOOR_OPEN_2 ? door_size - a : a);
5362 int i = p + door_skip;
5364 if (door_2.anim_mode & ANIM_STATIC_PANEL)
5366 BlitBitmap(bitmap_db_door, drawto,
5367 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2,
5368 VXSIZE, VYSIZE, VX, VY);
5370 else if (x <= VYSIZE)
5372 BlitBitmap(bitmap_db_door, drawto,
5373 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + p / 2,
5374 VXSIZE, VYSIZE - p / 2, VX, VY);
5376 ClearRectangle(drawto, VX, VY + VYSIZE - p / 2, VXSIZE, p / 2);
5379 if (door_2.anim_mode & ANIM_HORIZONTAL && x <= VXSIZE)
5381 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
5382 int dst1_x = VX + VXSIZE - i, dst1_y = VY;
5383 int src2_x = VXSIZE - i, src2_y = DOOR_GFX_PAGEY2;
5384 int dst2_x = VX, dst2_y = VY;
5385 int width = i, height = VYSIZE;
5387 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5388 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5391 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5392 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5395 else if (door_2.anim_mode & ANIM_VERTICAL && x <= VYSIZE)
5397 int src1_x = VXSIZE, src1_y = DOOR_GFX_PAGEY2;
5398 int dst1_x = VX, dst1_y = VY + VYSIZE - i;
5399 int src2_x = 0, src2_y = DOOR_GFX_PAGEY2 + VYSIZE - i;
5400 int dst2_x = VX, dst2_y = VY;
5401 int width = VXSIZE, height = i;
5403 SetClipOrigin(bitmap, gc, dst1_x - src1_x, dst1_y - src1_y);
5404 BlitBitmapMasked(bitmap, drawto, src1_x, src1_y, width, height,
5407 SetClipOrigin(bitmap, gc, dst2_x - src2_x, dst2_y - src2_y);
5408 BlitBitmapMasked(bitmap, drawto, src2_x, src2_y, width, height,
5411 else if (x <= VXSIZE) /* ANIM_DEFAULT */
5413 int j = (door_2.anim_mode == ANIM_DEFAULT ? (VXSIZE - i) / 3 : 0);
5415 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
5416 BlitBitmapMasked(bitmap, drawto,
5417 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
5418 VX + VXSIZE - i, VY + j);
5419 SetClipOrigin(bitmap, gc,
5420 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
5421 BlitBitmapMasked(bitmap, drawto,
5422 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
5425 BlitBitmapMasked(bitmap, drawto,
5426 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
5427 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
5428 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
5429 BlitBitmapMasked(bitmap, drawto,
5430 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
5432 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
5435 redraw_mask |= REDRAW_DOOR_2;
5436 door_2_done = (a == VXSIZE);
5439 if (!(door_state & DOOR_NO_DELAY))
5443 if (game_status == GAME_MODE_MAIN)
5446 WaitUntilDelayReached(&door_delay, door_delay_value);
5451 if (door_state & DOOR_ACTION_1)
5452 door1 = door_state & DOOR_ACTION_1;
5453 if (door_state & DOOR_ACTION_2)
5454 door2 = door_state & DOOR_ACTION_2;
5456 return (door1 | door2);
5459 void DrawSpecialEditorDoor()
5461 /* draw bigger toolbox window */
5462 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
5463 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
5465 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5466 EX - 6, VY - 4, EXSIZE + 12, EYSIZE - VYSIZE + 4,
5469 redraw_mask |= REDRAW_ALL;
5472 void UndrawSpecialEditorDoor()
5474 /* draw normal tape recorder window */
5475 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
5476 EX - 6, EY - 12, EXSIZE + 12, EYSIZE - VYSIZE + 12,
5479 redraw_mask |= REDRAW_ALL;
5483 /* ---------- new tool button stuff ---------------------------------------- */
5490 struct TextPosInfo *pos;
5493 } toolbutton_info[NUM_TOOL_BUTTONS] =
5496 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
5497 TOOL_CTRL_ID_YES, "yes"
5500 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
5501 TOOL_CTRL_ID_NO, "no"
5504 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
5505 TOOL_CTRL_ID_CONFIRM, "confirm"
5508 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
5509 TOOL_CTRL_ID_PLAYER_1, "player 1"
5512 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
5513 TOOL_CTRL_ID_PLAYER_2, "player 2"
5516 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
5517 TOOL_CTRL_ID_PLAYER_3, "player 3"
5520 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
5521 TOOL_CTRL_ID_PLAYER_4, "player 4"
5525 void CreateToolButtons()
5529 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5531 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
5532 struct TextPosInfo *pos = toolbutton_info[i].pos;
5533 struct GadgetInfo *gi;
5534 Bitmap *deco_bitmap = None;
5535 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5536 unsigned int event_mask = GD_EVENT_RELEASED;
5539 int gd_x = gfx->src_x;
5540 int gd_y = gfx->src_y;
5541 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
5542 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
5545 if (global.use_envelope_request)
5546 setRequestPosition(&dx, &dy, TRUE);
5548 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5550 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5552 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
5553 pos->size, &deco_bitmap, &deco_x, &deco_y);
5554 deco_xpos = (gfx->width - pos->size) / 2;
5555 deco_ypos = (gfx->height - pos->size) / 2;
5558 gi = CreateGadget(GDI_CUSTOM_ID, id,
5559 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5562 GDI_WIDTH, gfx->width,
5563 GDI_HEIGHT, gfx->height,
5564 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5565 GDI_STATE, GD_BUTTON_UNPRESSED,
5566 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
5567 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
5568 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5569 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5570 GDI_DECORATION_SIZE, pos->size, pos->size,
5571 GDI_DECORATION_SHIFTING, 1, 1,
5572 GDI_DIRECT_DRAW, FALSE,
5573 GDI_EVENT_MASK, event_mask,
5574 GDI_CALLBACK_ACTION, HandleToolButtons,
5578 Error(ERR_EXIT, "cannot create gadget");
5580 tool_gadget[id] = gi;
5586 /* graphic position values for tool buttons */
5587 #define TOOL_BUTTON_YES_XPOS 2
5588 #define TOOL_BUTTON_YES_YPOS 250
5589 #define TOOL_BUTTON_YES_GFX_YPOS 0
5590 #define TOOL_BUTTON_YES_XSIZE 46
5591 #define TOOL_BUTTON_YES_YSIZE 28
5592 #define TOOL_BUTTON_NO_XPOS 52
5593 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
5594 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
5595 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
5596 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
5597 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
5598 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
5599 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
5600 #define TOOL_BUTTON_CONFIRM_XSIZE 96
5601 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
5602 #define TOOL_BUTTON_PLAYER_XSIZE 30
5603 #define TOOL_BUTTON_PLAYER_YSIZE 30
5604 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
5605 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
5606 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
5607 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
5608 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5609 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
5610 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5611 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
5612 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5613 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
5614 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
5615 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
5616 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5617 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
5618 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5619 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
5620 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5621 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
5622 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
5623 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
5632 } toolbutton_info[NUM_TOOL_BUTTONS] =
5635 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
5636 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
5637 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
5642 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
5643 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
5644 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
5649 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
5650 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
5651 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
5652 TOOL_CTRL_ID_CONFIRM,
5656 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5657 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
5658 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5659 TOOL_CTRL_ID_PLAYER_1,
5663 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5664 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
5665 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5666 TOOL_CTRL_ID_PLAYER_2,
5670 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5671 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
5672 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5673 TOOL_CTRL_ID_PLAYER_3,
5677 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
5678 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
5679 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
5680 TOOL_CTRL_ID_PLAYER_4,
5685 void CreateToolButtons()
5689 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5691 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
5692 Bitmap *deco_bitmap = None;
5693 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
5694 struct GadgetInfo *gi;
5695 unsigned int event_mask;
5696 int gd_xoffset, gd_yoffset;
5697 int gd_x1, gd_x2, gd_y;
5700 event_mask = GD_EVENT_RELEASED;
5702 gd_xoffset = toolbutton_info[i].xpos;
5703 gd_yoffset = toolbutton_info[i].ypos;
5704 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
5705 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
5706 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
5708 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
5710 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
5712 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr),
5713 &deco_bitmap, &deco_x, &deco_y);
5714 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
5715 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
5718 gi = CreateGadget(GDI_CUSTOM_ID, id,
5719 GDI_INFO_TEXT, toolbutton_info[i].infotext,
5720 GDI_X, DX + toolbutton_info[i].x,
5721 GDI_Y, DY + toolbutton_info[i].y,
5722 GDI_WIDTH, toolbutton_info[i].width,
5723 GDI_HEIGHT, toolbutton_info[i].height,
5724 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
5725 GDI_STATE, GD_BUTTON_UNPRESSED,
5726 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
5727 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
5728 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
5729 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
5730 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
5731 GDI_DECORATION_SHIFTING, 1, 1,
5732 GDI_DIRECT_DRAW, FALSE,
5733 GDI_EVENT_MASK, event_mask,
5734 GDI_CALLBACK_ACTION, HandleToolButtons,
5738 Error(ERR_EXIT, "cannot create gadget");
5740 tool_gadget[id] = gi;
5746 void FreeToolButtons()
5750 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5751 FreeGadget(tool_gadget[i]);
5754 static void UnmapToolButtons()
5758 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
5759 UnmapGadget(tool_gadget[i]);
5762 static void HandleToolButtons(struct GadgetInfo *gi)
5764 request_gadget_id = gi->custom_id;
5767 static struct Mapping_EM_to_RND_object
5770 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
5771 boolean is_backside; /* backside of moving element */
5777 em_object_mapping_list[] =
5780 Xblank, TRUE, FALSE,
5784 Yacid_splash_eB, FALSE, FALSE,
5785 EL_ACID_SPLASH_RIGHT, -1, -1
5788 Yacid_splash_wB, FALSE, FALSE,
5789 EL_ACID_SPLASH_LEFT, -1, -1
5792 #ifdef EM_ENGINE_BAD_ROLL
5794 Xstone_force_e, FALSE, FALSE,
5795 EL_ROCK, -1, MV_BIT_RIGHT
5798 Xstone_force_w, FALSE, FALSE,
5799 EL_ROCK, -1, MV_BIT_LEFT
5802 Xnut_force_e, FALSE, FALSE,
5803 EL_NUT, -1, MV_BIT_RIGHT
5806 Xnut_force_w, FALSE, FALSE,
5807 EL_NUT, -1, MV_BIT_LEFT
5810 Xspring_force_e, FALSE, FALSE,
5811 EL_SPRING, -1, MV_BIT_RIGHT
5814 Xspring_force_w, FALSE, FALSE,
5815 EL_SPRING, -1, MV_BIT_LEFT
5818 Xemerald_force_e, FALSE, FALSE,
5819 EL_EMERALD, -1, MV_BIT_RIGHT
5822 Xemerald_force_w, FALSE, FALSE,
5823 EL_EMERALD, -1, MV_BIT_LEFT
5826 Xdiamond_force_e, FALSE, FALSE,
5827 EL_DIAMOND, -1, MV_BIT_RIGHT
5830 Xdiamond_force_w, FALSE, FALSE,
5831 EL_DIAMOND, -1, MV_BIT_LEFT
5834 Xbomb_force_e, FALSE, FALSE,
5835 EL_BOMB, -1, MV_BIT_RIGHT
5838 Xbomb_force_w, FALSE, FALSE,
5839 EL_BOMB, -1, MV_BIT_LEFT
5841 #endif /* EM_ENGINE_BAD_ROLL */
5844 Xstone, TRUE, FALSE,
5848 Xstone_pause, FALSE, FALSE,
5852 Xstone_fall, FALSE, FALSE,
5856 Ystone_s, FALSE, FALSE,
5857 EL_ROCK, ACTION_FALLING, -1
5860 Ystone_sB, FALSE, TRUE,
5861 EL_ROCK, ACTION_FALLING, -1
5864 Ystone_e, FALSE, FALSE,
5865 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5868 Ystone_eB, FALSE, TRUE,
5869 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
5872 Ystone_w, FALSE, FALSE,
5873 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5876 Ystone_wB, FALSE, TRUE,
5877 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
5884 Xnut_pause, FALSE, FALSE,
5888 Xnut_fall, FALSE, FALSE,
5892 Ynut_s, FALSE, FALSE,
5893 EL_NUT, ACTION_FALLING, -1
5896 Ynut_sB, FALSE, TRUE,
5897 EL_NUT, ACTION_FALLING, -1
5900 Ynut_e, FALSE, FALSE,
5901 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5904 Ynut_eB, FALSE, TRUE,
5905 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
5908 Ynut_w, FALSE, FALSE,
5909 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5912 Ynut_wB, FALSE, TRUE,
5913 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
5916 Xbug_n, TRUE, FALSE,
5920 Xbug_e, TRUE, FALSE,
5921 EL_BUG_RIGHT, -1, -1
5924 Xbug_s, TRUE, FALSE,
5928 Xbug_w, TRUE, FALSE,
5932 Xbug_gon, FALSE, FALSE,
5936 Xbug_goe, FALSE, FALSE,
5937 EL_BUG_RIGHT, -1, -1
5940 Xbug_gos, FALSE, FALSE,
5944 Xbug_gow, FALSE, FALSE,
5948 Ybug_n, FALSE, FALSE,
5949 EL_BUG, ACTION_MOVING, MV_BIT_UP
5952 Ybug_nB, FALSE, TRUE,
5953 EL_BUG, ACTION_MOVING, MV_BIT_UP
5956 Ybug_e, FALSE, FALSE,
5957 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5960 Ybug_eB, FALSE, TRUE,
5961 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
5964 Ybug_s, FALSE, FALSE,
5965 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5968 Ybug_sB, FALSE, TRUE,
5969 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
5972 Ybug_w, FALSE, FALSE,
5973 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5976 Ybug_wB, FALSE, TRUE,
5977 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
5980 Ybug_w_n, FALSE, FALSE,
5981 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
5984 Ybug_n_e, FALSE, FALSE,
5985 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
5988 Ybug_e_s, FALSE, FALSE,
5989 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
5992 Ybug_s_w, FALSE, FALSE,
5993 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
5996 Ybug_e_n, FALSE, FALSE,
5997 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6000 Ybug_s_e, FALSE, FALSE,
6001 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6004 Ybug_w_s, FALSE, FALSE,
6005 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6008 Ybug_n_w, FALSE, FALSE,
6009 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6012 Ybug_stone, FALSE, FALSE,
6013 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
6016 Ybug_spring, FALSE, FALSE,
6017 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
6020 Xtank_n, TRUE, FALSE,
6021 EL_SPACESHIP_UP, -1, -1
6024 Xtank_e, TRUE, FALSE,
6025 EL_SPACESHIP_RIGHT, -1, -1
6028 Xtank_s, TRUE, FALSE,
6029 EL_SPACESHIP_DOWN, -1, -1
6032 Xtank_w, TRUE, FALSE,
6033 EL_SPACESHIP_LEFT, -1, -1
6036 Xtank_gon, FALSE, FALSE,
6037 EL_SPACESHIP_UP, -1, -1
6040 Xtank_goe, FALSE, FALSE,
6041 EL_SPACESHIP_RIGHT, -1, -1
6044 Xtank_gos, FALSE, FALSE,
6045 EL_SPACESHIP_DOWN, -1, -1
6048 Xtank_gow, FALSE, FALSE,
6049 EL_SPACESHIP_LEFT, -1, -1
6052 Ytank_n, FALSE, FALSE,
6053 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6056 Ytank_nB, FALSE, TRUE,
6057 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
6060 Ytank_e, FALSE, FALSE,
6061 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6064 Ytank_eB, FALSE, TRUE,
6065 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
6068 Ytank_s, FALSE, FALSE,
6069 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6072 Ytank_sB, FALSE, TRUE,
6073 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
6076 Ytank_w, FALSE, FALSE,
6077 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6080 Ytank_wB, FALSE, TRUE,
6081 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
6084 Ytank_w_n, FALSE, FALSE,
6085 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
6088 Ytank_n_e, FALSE, FALSE,
6089 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
6092 Ytank_e_s, FALSE, FALSE,
6093 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
6096 Ytank_s_w, FALSE, FALSE,
6097 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
6100 Ytank_e_n, FALSE, FALSE,
6101 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
6104 Ytank_s_e, FALSE, FALSE,
6105 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
6108 Ytank_w_s, FALSE, FALSE,
6109 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
6112 Ytank_n_w, FALSE, FALSE,
6113 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
6116 Ytank_stone, FALSE, FALSE,
6117 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
6120 Ytank_spring, FALSE, FALSE,
6121 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
6124 Xandroid, TRUE, FALSE,
6125 EL_EMC_ANDROID, ACTION_ACTIVE, -1
6128 Xandroid_1_n, FALSE, FALSE,
6129 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6132 Xandroid_2_n, FALSE, FALSE,
6133 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
6136 Xandroid_1_e, FALSE, FALSE,
6137 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6140 Xandroid_2_e, FALSE, FALSE,
6141 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
6144 Xandroid_1_w, FALSE, FALSE,
6145 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6148 Xandroid_2_w, FALSE, FALSE,
6149 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
6152 Xandroid_1_s, FALSE, FALSE,
6153 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6156 Xandroid_2_s, FALSE, FALSE,
6157 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
6160 Yandroid_n, FALSE, FALSE,
6161 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6164 Yandroid_nB, FALSE, TRUE,
6165 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
6168 Yandroid_ne, FALSE, FALSE,
6169 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
6172 Yandroid_neB, FALSE, TRUE,
6173 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
6176 Yandroid_e, FALSE, FALSE,
6177 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6180 Yandroid_eB, FALSE, TRUE,
6181 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
6184 Yandroid_se, FALSE, FALSE,
6185 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
6188 Yandroid_seB, FALSE, TRUE,
6189 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
6192 Yandroid_s, FALSE, FALSE,
6193 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6196 Yandroid_sB, FALSE, TRUE,
6197 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
6200 Yandroid_sw, FALSE, FALSE,
6201 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
6204 Yandroid_swB, FALSE, TRUE,
6205 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
6208 Yandroid_w, FALSE, FALSE,
6209 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6212 Yandroid_wB, FALSE, TRUE,
6213 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
6216 Yandroid_nw, FALSE, FALSE,
6217 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
6220 Yandroid_nwB, FALSE, TRUE,
6221 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
6224 Xspring, TRUE, FALSE,
6228 Xspring_pause, FALSE, FALSE,
6232 Xspring_e, FALSE, FALSE,
6236 Xspring_w, FALSE, FALSE,
6240 Xspring_fall, FALSE, FALSE,
6244 Yspring_s, FALSE, FALSE,
6245 EL_SPRING, ACTION_FALLING, -1
6248 Yspring_sB, FALSE, TRUE,
6249 EL_SPRING, ACTION_FALLING, -1
6252 Yspring_e, FALSE, FALSE,
6253 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6256 Yspring_eB, FALSE, TRUE,
6257 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
6260 Yspring_w, FALSE, FALSE,
6261 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6264 Yspring_wB, FALSE, TRUE,
6265 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
6268 Yspring_kill_e, FALSE, FALSE,
6269 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6272 Yspring_kill_eB, FALSE, TRUE,
6273 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
6276 Yspring_kill_w, FALSE, FALSE,
6277 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6280 Yspring_kill_wB, FALSE, TRUE,
6281 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
6284 Xeater_n, TRUE, FALSE,
6285 EL_YAMYAM_UP, -1, -1
6288 Xeater_e, TRUE, FALSE,
6289 EL_YAMYAM_RIGHT, -1, -1
6292 Xeater_w, TRUE, FALSE,
6293 EL_YAMYAM_LEFT, -1, -1
6296 Xeater_s, TRUE, FALSE,
6297 EL_YAMYAM_DOWN, -1, -1
6300 Yeater_n, FALSE, FALSE,
6301 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6304 Yeater_nB, FALSE, TRUE,
6305 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
6308 Yeater_e, FALSE, FALSE,
6309 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6312 Yeater_eB, FALSE, TRUE,
6313 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
6316 Yeater_s, FALSE, FALSE,
6317 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6320 Yeater_sB, FALSE, TRUE,
6321 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
6324 Yeater_w, FALSE, FALSE,
6325 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6328 Yeater_wB, FALSE, TRUE,
6329 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
6332 Yeater_stone, FALSE, FALSE,
6333 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
6336 Yeater_spring, FALSE, FALSE,
6337 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
6340 Xalien, TRUE, FALSE,
6344 Xalien_pause, FALSE, FALSE,
6348 Yalien_n, FALSE, FALSE,
6349 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6352 Yalien_nB, FALSE, TRUE,
6353 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
6356 Yalien_e, FALSE, FALSE,
6357 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6360 Yalien_eB, FALSE, TRUE,
6361 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
6364 Yalien_s, FALSE, FALSE,
6365 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6368 Yalien_sB, FALSE, TRUE,
6369 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
6372 Yalien_w, FALSE, FALSE,
6373 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6376 Yalien_wB, FALSE, TRUE,
6377 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
6380 Yalien_stone, FALSE, FALSE,
6381 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
6384 Yalien_spring, FALSE, FALSE,
6385 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
6388 Xemerald, TRUE, FALSE,
6392 Xemerald_pause, FALSE, FALSE,
6396 Xemerald_fall, FALSE, FALSE,
6400 Xemerald_shine, FALSE, FALSE,
6401 EL_EMERALD, ACTION_TWINKLING, -1
6404 Yemerald_s, FALSE, FALSE,
6405 EL_EMERALD, ACTION_FALLING, -1
6408 Yemerald_sB, FALSE, TRUE,
6409 EL_EMERALD, ACTION_FALLING, -1
6412 Yemerald_e, FALSE, FALSE,
6413 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6416 Yemerald_eB, FALSE, TRUE,
6417 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
6420 Yemerald_w, FALSE, FALSE,
6421 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6424 Yemerald_wB, FALSE, TRUE,
6425 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
6428 Yemerald_eat, FALSE, FALSE,
6429 EL_EMERALD, ACTION_COLLECTING, -1
6432 Yemerald_stone, FALSE, FALSE,
6433 EL_NUT, ACTION_BREAKING, -1
6436 Xdiamond, TRUE, FALSE,
6440 Xdiamond_pause, FALSE, FALSE,
6444 Xdiamond_fall, FALSE, FALSE,
6448 Xdiamond_shine, FALSE, FALSE,
6449 EL_DIAMOND, ACTION_TWINKLING, -1
6452 Ydiamond_s, FALSE, FALSE,
6453 EL_DIAMOND, ACTION_FALLING, -1
6456 Ydiamond_sB, FALSE, TRUE,
6457 EL_DIAMOND, ACTION_FALLING, -1
6460 Ydiamond_e, FALSE, FALSE,
6461 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6464 Ydiamond_eB, FALSE, TRUE,
6465 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
6468 Ydiamond_w, FALSE, FALSE,
6469 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6472 Ydiamond_wB, FALSE, TRUE,
6473 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
6476 Ydiamond_eat, FALSE, FALSE,
6477 EL_DIAMOND, ACTION_COLLECTING, -1
6480 Ydiamond_stone, FALSE, FALSE,
6481 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
6484 Xdrip_fall, TRUE, FALSE,
6485 EL_AMOEBA_DROP, -1, -1
6488 Xdrip_stretch, FALSE, FALSE,
6489 EL_AMOEBA_DROP, ACTION_FALLING, -1
6492 Xdrip_stretchB, FALSE, TRUE,
6493 EL_AMOEBA_DROP, ACTION_FALLING, -1
6496 Xdrip_eat, FALSE, FALSE,
6497 EL_AMOEBA_DROP, ACTION_GROWING, -1
6500 Ydrip_s1, FALSE, FALSE,
6501 EL_AMOEBA_DROP, ACTION_FALLING, -1
6504 Ydrip_s1B, FALSE, TRUE,
6505 EL_AMOEBA_DROP, ACTION_FALLING, -1
6508 Ydrip_s2, FALSE, FALSE,
6509 EL_AMOEBA_DROP, ACTION_FALLING, -1
6512 Ydrip_s2B, FALSE, TRUE,
6513 EL_AMOEBA_DROP, ACTION_FALLING, -1
6520 Xbomb_pause, FALSE, FALSE,
6524 Xbomb_fall, FALSE, FALSE,
6528 Ybomb_s, FALSE, FALSE,
6529 EL_BOMB, ACTION_FALLING, -1
6532 Ybomb_sB, FALSE, TRUE,
6533 EL_BOMB, ACTION_FALLING, -1
6536 Ybomb_e, FALSE, FALSE,
6537 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6540 Ybomb_eB, FALSE, TRUE,
6541 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
6544 Ybomb_w, FALSE, FALSE,
6545 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6548 Ybomb_wB, FALSE, TRUE,
6549 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
6552 Ybomb_eat, FALSE, FALSE,
6553 EL_BOMB, ACTION_ACTIVATING, -1
6556 Xballoon, TRUE, FALSE,
6560 Yballoon_n, FALSE, FALSE,
6561 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6564 Yballoon_nB, FALSE, TRUE,
6565 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
6568 Yballoon_e, FALSE, FALSE,
6569 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6572 Yballoon_eB, FALSE, TRUE,
6573 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
6576 Yballoon_s, FALSE, FALSE,
6577 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6580 Yballoon_sB, FALSE, TRUE,
6581 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
6584 Yballoon_w, FALSE, FALSE,
6585 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6588 Yballoon_wB, FALSE, TRUE,
6589 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
6592 Xgrass, TRUE, FALSE,
6593 EL_EMC_GRASS, -1, -1
6596 Ygrass_nB, FALSE, FALSE,
6597 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
6600 Ygrass_eB, FALSE, FALSE,
6601 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
6604 Ygrass_sB, FALSE, FALSE,
6605 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
6608 Ygrass_wB, FALSE, FALSE,
6609 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
6616 Ydirt_nB, FALSE, FALSE,
6617 EL_SAND, ACTION_DIGGING, MV_BIT_UP
6620 Ydirt_eB, FALSE, FALSE,
6621 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
6624 Ydirt_sB, FALSE, FALSE,
6625 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
6628 Ydirt_wB, FALSE, FALSE,
6629 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
6632 Xacid_ne, TRUE, FALSE,
6633 EL_ACID_POOL_TOPRIGHT, -1, -1
6636 Xacid_se, TRUE, FALSE,
6637 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
6640 Xacid_s, TRUE, FALSE,
6641 EL_ACID_POOL_BOTTOM, -1, -1
6644 Xacid_sw, TRUE, FALSE,
6645 EL_ACID_POOL_BOTTOMLEFT, -1, -1
6648 Xacid_nw, TRUE, FALSE,
6649 EL_ACID_POOL_TOPLEFT, -1, -1
6652 Xacid_1, TRUE, FALSE,
6656 Xacid_2, FALSE, FALSE,
6660 Xacid_3, FALSE, FALSE,
6664 Xacid_4, FALSE, FALSE,
6668 Xacid_5, FALSE, FALSE,
6672 Xacid_6, FALSE, FALSE,
6676 Xacid_7, FALSE, FALSE,
6680 Xacid_8, FALSE, FALSE,
6684 Xball_1, TRUE, FALSE,
6685 EL_EMC_MAGIC_BALL, -1, -1
6688 Xball_1B, FALSE, FALSE,
6689 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6692 Xball_2, FALSE, FALSE,
6693 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6696 Xball_2B, FALSE, FALSE,
6697 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
6700 Yball_eat, FALSE, FALSE,
6701 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
6704 Ykey_1_eat, FALSE, FALSE,
6705 EL_EM_KEY_1, ACTION_COLLECTING, -1
6708 Ykey_2_eat, FALSE, FALSE,
6709 EL_EM_KEY_2, ACTION_COLLECTING, -1
6712 Ykey_3_eat, FALSE, FALSE,
6713 EL_EM_KEY_3, ACTION_COLLECTING, -1
6716 Ykey_4_eat, FALSE, FALSE,
6717 EL_EM_KEY_4, ACTION_COLLECTING, -1
6720 Ykey_5_eat, FALSE, FALSE,
6721 EL_EMC_KEY_5, ACTION_COLLECTING, -1
6724 Ykey_6_eat, FALSE, FALSE,
6725 EL_EMC_KEY_6, ACTION_COLLECTING, -1
6728 Ykey_7_eat, FALSE, FALSE,
6729 EL_EMC_KEY_7, ACTION_COLLECTING, -1
6732 Ykey_8_eat, FALSE, FALSE,
6733 EL_EMC_KEY_8, ACTION_COLLECTING, -1
6736 Ylenses_eat, FALSE, FALSE,
6737 EL_EMC_LENSES, ACTION_COLLECTING, -1
6740 Ymagnify_eat, FALSE, FALSE,
6741 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
6744 Ygrass_eat, FALSE, FALSE,
6745 EL_EMC_GRASS, ACTION_SNAPPING, -1
6748 Ydirt_eat, FALSE, FALSE,
6749 EL_SAND, ACTION_SNAPPING, -1
6752 Xgrow_ns, TRUE, FALSE,
6753 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
6756 Ygrow_ns_eat, FALSE, FALSE,
6757 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
6760 Xgrow_ew, TRUE, FALSE,
6761 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
6764 Ygrow_ew_eat, FALSE, FALSE,
6765 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
6768 Xwonderwall, TRUE, FALSE,
6769 EL_MAGIC_WALL, -1, -1
6772 XwonderwallB, FALSE, FALSE,
6773 EL_MAGIC_WALL, ACTION_ACTIVE, -1
6776 Xamoeba_1, TRUE, FALSE,
6777 EL_AMOEBA_DRY, ACTION_OTHER, -1
6780 Xamoeba_2, FALSE, FALSE,
6781 EL_AMOEBA_DRY, ACTION_OTHER, -1
6784 Xamoeba_3, FALSE, FALSE,
6785 EL_AMOEBA_DRY, ACTION_OTHER, -1
6788 Xamoeba_4, FALSE, FALSE,
6789 EL_AMOEBA_DRY, ACTION_OTHER, -1
6792 Xamoeba_5, TRUE, FALSE,
6793 EL_AMOEBA_WET, ACTION_OTHER, -1
6796 Xamoeba_6, FALSE, FALSE,
6797 EL_AMOEBA_WET, ACTION_OTHER, -1
6800 Xamoeba_7, FALSE, FALSE,
6801 EL_AMOEBA_WET, ACTION_OTHER, -1
6804 Xamoeba_8, FALSE, FALSE,
6805 EL_AMOEBA_WET, ACTION_OTHER, -1
6808 Xdoor_1, TRUE, FALSE,
6809 EL_EM_GATE_1, -1, -1
6812 Xdoor_2, TRUE, FALSE,
6813 EL_EM_GATE_2, -1, -1
6816 Xdoor_3, TRUE, FALSE,
6817 EL_EM_GATE_3, -1, -1
6820 Xdoor_4, TRUE, FALSE,
6821 EL_EM_GATE_4, -1, -1
6824 Xdoor_5, TRUE, FALSE,
6825 EL_EMC_GATE_5, -1, -1
6828 Xdoor_6, TRUE, FALSE,
6829 EL_EMC_GATE_6, -1, -1
6832 Xdoor_7, TRUE, FALSE,
6833 EL_EMC_GATE_7, -1, -1
6836 Xdoor_8, TRUE, FALSE,
6837 EL_EMC_GATE_8, -1, -1
6840 Xkey_1, TRUE, FALSE,
6844 Xkey_2, TRUE, FALSE,
6848 Xkey_3, TRUE, FALSE,
6852 Xkey_4, TRUE, FALSE,
6856 Xkey_5, TRUE, FALSE,
6857 EL_EMC_KEY_5, -1, -1
6860 Xkey_6, TRUE, FALSE,
6861 EL_EMC_KEY_6, -1, -1
6864 Xkey_7, TRUE, FALSE,
6865 EL_EMC_KEY_7, -1, -1
6868 Xkey_8, TRUE, FALSE,
6869 EL_EMC_KEY_8, -1, -1
6872 Xwind_n, TRUE, FALSE,
6873 EL_BALLOON_SWITCH_UP, -1, -1
6876 Xwind_e, TRUE, FALSE,
6877 EL_BALLOON_SWITCH_RIGHT, -1, -1
6880 Xwind_s, TRUE, FALSE,
6881 EL_BALLOON_SWITCH_DOWN, -1, -1
6884 Xwind_w, TRUE, FALSE,
6885 EL_BALLOON_SWITCH_LEFT, -1, -1
6888 Xwind_nesw, TRUE, FALSE,
6889 EL_BALLOON_SWITCH_ANY, -1, -1
6892 Xwind_stop, TRUE, FALSE,
6893 EL_BALLOON_SWITCH_NONE, -1, -1
6897 EL_EM_EXIT_CLOSED, -1, -1
6900 Xexit_1, TRUE, FALSE,
6901 EL_EM_EXIT_OPEN, -1, -1
6904 Xexit_2, FALSE, FALSE,
6905 EL_EM_EXIT_OPEN, -1, -1
6908 Xexit_3, FALSE, FALSE,
6909 EL_EM_EXIT_OPEN, -1, -1
6912 Xdynamite, TRUE, FALSE,
6913 EL_EM_DYNAMITE, -1, -1
6916 Ydynamite_eat, FALSE, FALSE,
6917 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
6920 Xdynamite_1, TRUE, FALSE,
6921 EL_EM_DYNAMITE_ACTIVE, -1, -1
6924 Xdynamite_2, FALSE, FALSE,
6925 EL_EM_DYNAMITE_ACTIVE, -1, -1
6928 Xdynamite_3, FALSE, FALSE,
6929 EL_EM_DYNAMITE_ACTIVE, -1, -1
6932 Xdynamite_4, FALSE, FALSE,
6933 EL_EM_DYNAMITE_ACTIVE, -1, -1
6936 Xbumper, TRUE, FALSE,
6937 EL_EMC_SPRING_BUMPER, -1, -1
6940 XbumperB, FALSE, FALSE,
6941 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
6944 Xwheel, TRUE, FALSE,
6945 EL_ROBOT_WHEEL, -1, -1
6948 XwheelB, FALSE, FALSE,
6949 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
6952 Xswitch, TRUE, FALSE,
6953 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
6956 XswitchB, FALSE, FALSE,
6957 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
6961 EL_QUICKSAND_EMPTY, -1, -1
6964 Xsand_stone, TRUE, FALSE,
6965 EL_QUICKSAND_FULL, -1, -1
6968 Xsand_stonein_1, FALSE, TRUE,
6969 EL_ROCK, ACTION_FILLING, -1
6972 Xsand_stonein_2, FALSE, TRUE,
6973 EL_ROCK, ACTION_FILLING, -1
6976 Xsand_stonein_3, FALSE, TRUE,
6977 EL_ROCK, ACTION_FILLING, -1
6980 Xsand_stonein_4, FALSE, TRUE,
6981 EL_ROCK, ACTION_FILLING, -1
6985 Xsand_stonesand_1, FALSE, FALSE,
6986 EL_QUICKSAND_EMPTYING, -1, -1
6989 Xsand_stonesand_2, FALSE, FALSE,
6990 EL_QUICKSAND_EMPTYING, -1, -1
6993 Xsand_stonesand_3, FALSE, FALSE,
6994 EL_QUICKSAND_EMPTYING, -1, -1
6997 Xsand_stonesand_4, FALSE, FALSE,
6998 EL_QUICKSAND_EMPTYING, -1, -1
7001 Xsand_stonesand_quickout_1, FALSE, FALSE,
7002 EL_QUICKSAND_EMPTYING, -1, -1
7005 Xsand_stonesand_quickout_2, FALSE, FALSE,
7006 EL_QUICKSAND_EMPTYING, -1, -1
7010 Xsand_stonesand_1, FALSE, FALSE,
7011 EL_QUICKSAND_FULL, -1, -1
7014 Xsand_stonesand_2, FALSE, FALSE,
7015 EL_QUICKSAND_FULL, -1, -1
7018 Xsand_stonesand_3, FALSE, FALSE,
7019 EL_QUICKSAND_FULL, -1, -1
7022 Xsand_stonesand_4, FALSE, FALSE,
7023 EL_QUICKSAND_FULL, -1, -1
7027 Xsand_stoneout_1, FALSE, FALSE,
7028 EL_ROCK, ACTION_EMPTYING, -1
7031 Xsand_stoneout_2, FALSE, FALSE,
7032 EL_ROCK, ACTION_EMPTYING, -1
7036 Xsand_sandstone_1, FALSE, FALSE,
7037 EL_QUICKSAND_FILLING, -1, -1
7040 Xsand_sandstone_2, FALSE, FALSE,
7041 EL_QUICKSAND_FILLING, -1, -1
7044 Xsand_sandstone_3, FALSE, FALSE,
7045 EL_QUICKSAND_FILLING, -1, -1
7048 Xsand_sandstone_4, FALSE, FALSE,
7049 EL_QUICKSAND_FILLING, -1, -1
7053 Xsand_sandstone_1, FALSE, FALSE,
7054 EL_QUICKSAND_FULL, -1, -1
7057 Xsand_sandstone_2, FALSE, FALSE,
7058 EL_QUICKSAND_FULL, -1, -1
7061 Xsand_sandstone_3, FALSE, FALSE,
7062 EL_QUICKSAND_FULL, -1, -1
7065 Xsand_sandstone_4, FALSE, FALSE,
7066 EL_QUICKSAND_FULL, -1, -1
7070 Xplant, TRUE, FALSE,
7071 EL_EMC_PLANT, -1, -1
7074 Yplant, FALSE, FALSE,
7075 EL_EMC_PLANT, -1, -1
7078 Xlenses, TRUE, FALSE,
7079 EL_EMC_LENSES, -1, -1
7082 Xmagnify, TRUE, FALSE,
7083 EL_EMC_MAGNIFIER, -1, -1
7086 Xdripper, TRUE, FALSE,
7087 EL_EMC_DRIPPER, -1, -1
7090 XdripperB, FALSE, FALSE,
7091 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
7094 Xfake_blank, TRUE, FALSE,
7095 EL_INVISIBLE_WALL, -1, -1
7098 Xfake_blankB, FALSE, FALSE,
7099 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
7102 Xfake_grass, TRUE, FALSE,
7103 EL_EMC_FAKE_GRASS, -1, -1
7106 Xfake_grassB, FALSE, FALSE,
7107 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
7110 Xfake_door_1, TRUE, FALSE,
7111 EL_EM_GATE_1_GRAY, -1, -1
7114 Xfake_door_2, TRUE, FALSE,
7115 EL_EM_GATE_2_GRAY, -1, -1
7118 Xfake_door_3, TRUE, FALSE,
7119 EL_EM_GATE_3_GRAY, -1, -1
7122 Xfake_door_4, TRUE, FALSE,
7123 EL_EM_GATE_4_GRAY, -1, -1
7126 Xfake_door_5, TRUE, FALSE,
7127 EL_EMC_GATE_5_GRAY, -1, -1
7130 Xfake_door_6, TRUE, FALSE,
7131 EL_EMC_GATE_6_GRAY, -1, -1
7134 Xfake_door_7, TRUE, FALSE,
7135 EL_EMC_GATE_7_GRAY, -1, -1
7138 Xfake_door_8, TRUE, FALSE,
7139 EL_EMC_GATE_8_GRAY, -1, -1
7142 Xfake_acid_1, TRUE, FALSE,
7143 EL_EMC_FAKE_ACID, -1, -1
7146 Xfake_acid_2, FALSE, FALSE,
7147 EL_EMC_FAKE_ACID, -1, -1
7150 Xfake_acid_3, FALSE, FALSE,
7151 EL_EMC_FAKE_ACID, -1, -1
7154 Xfake_acid_4, FALSE, FALSE,
7155 EL_EMC_FAKE_ACID, -1, -1
7158 Xfake_acid_5, FALSE, FALSE,
7159 EL_EMC_FAKE_ACID, -1, -1
7162 Xfake_acid_6, FALSE, FALSE,
7163 EL_EMC_FAKE_ACID, -1, -1
7166 Xfake_acid_7, FALSE, FALSE,
7167 EL_EMC_FAKE_ACID, -1, -1
7170 Xfake_acid_8, FALSE, FALSE,
7171 EL_EMC_FAKE_ACID, -1, -1
7174 Xsteel_1, TRUE, FALSE,
7175 EL_STEELWALL, -1, -1
7178 Xsteel_2, TRUE, FALSE,
7179 EL_EMC_STEELWALL_2, -1, -1
7182 Xsteel_3, TRUE, FALSE,
7183 EL_EMC_STEELWALL_3, -1, -1
7186 Xsteel_4, TRUE, FALSE,
7187 EL_EMC_STEELWALL_4, -1, -1
7190 Xwall_1, TRUE, FALSE,
7194 Xwall_2, TRUE, FALSE,
7195 EL_EMC_WALL_14, -1, -1
7198 Xwall_3, TRUE, FALSE,
7199 EL_EMC_WALL_15, -1, -1
7202 Xwall_4, TRUE, FALSE,
7203 EL_EMC_WALL_16, -1, -1
7206 Xround_wall_1, TRUE, FALSE,
7207 EL_WALL_SLIPPERY, -1, -1
7210 Xround_wall_2, TRUE, FALSE,
7211 EL_EMC_WALL_SLIPPERY_2, -1, -1
7214 Xround_wall_3, TRUE, FALSE,
7215 EL_EMC_WALL_SLIPPERY_3, -1, -1
7218 Xround_wall_4, TRUE, FALSE,
7219 EL_EMC_WALL_SLIPPERY_4, -1, -1
7222 Xdecor_1, TRUE, FALSE,
7223 EL_EMC_WALL_8, -1, -1
7226 Xdecor_2, TRUE, FALSE,
7227 EL_EMC_WALL_6, -1, -1
7230 Xdecor_3, TRUE, FALSE,
7231 EL_EMC_WALL_4, -1, -1
7234 Xdecor_4, TRUE, FALSE,
7235 EL_EMC_WALL_7, -1, -1
7238 Xdecor_5, TRUE, FALSE,
7239 EL_EMC_WALL_5, -1, -1
7242 Xdecor_6, TRUE, FALSE,
7243 EL_EMC_WALL_9, -1, -1
7246 Xdecor_7, TRUE, FALSE,
7247 EL_EMC_WALL_10, -1, -1
7250 Xdecor_8, TRUE, FALSE,
7251 EL_EMC_WALL_1, -1, -1
7254 Xdecor_9, TRUE, FALSE,
7255 EL_EMC_WALL_2, -1, -1
7258 Xdecor_10, TRUE, FALSE,
7259 EL_EMC_WALL_3, -1, -1
7262 Xdecor_11, TRUE, FALSE,
7263 EL_EMC_WALL_11, -1, -1
7266 Xdecor_12, TRUE, FALSE,
7267 EL_EMC_WALL_12, -1, -1
7270 Xalpha_0, TRUE, FALSE,
7271 EL_CHAR('0'), -1, -1
7274 Xalpha_1, TRUE, FALSE,
7275 EL_CHAR('1'), -1, -1
7278 Xalpha_2, TRUE, FALSE,
7279 EL_CHAR('2'), -1, -1
7282 Xalpha_3, TRUE, FALSE,
7283 EL_CHAR('3'), -1, -1
7286 Xalpha_4, TRUE, FALSE,
7287 EL_CHAR('4'), -1, -1
7290 Xalpha_5, TRUE, FALSE,
7291 EL_CHAR('5'), -1, -1
7294 Xalpha_6, TRUE, FALSE,
7295 EL_CHAR('6'), -1, -1
7298 Xalpha_7, TRUE, FALSE,
7299 EL_CHAR('7'), -1, -1
7302 Xalpha_8, TRUE, FALSE,
7303 EL_CHAR('8'), -1, -1
7306 Xalpha_9, TRUE, FALSE,
7307 EL_CHAR('9'), -1, -1
7310 Xalpha_excla, TRUE, FALSE,
7311 EL_CHAR('!'), -1, -1
7314 Xalpha_quote, TRUE, FALSE,
7315 EL_CHAR('"'), -1, -1
7318 Xalpha_comma, TRUE, FALSE,
7319 EL_CHAR(','), -1, -1
7322 Xalpha_minus, TRUE, FALSE,
7323 EL_CHAR('-'), -1, -1
7326 Xalpha_perio, TRUE, FALSE,
7327 EL_CHAR('.'), -1, -1
7330 Xalpha_colon, TRUE, FALSE,
7331 EL_CHAR(':'), -1, -1
7334 Xalpha_quest, TRUE, FALSE,
7335 EL_CHAR('?'), -1, -1
7338 Xalpha_a, TRUE, FALSE,
7339 EL_CHAR('A'), -1, -1
7342 Xalpha_b, TRUE, FALSE,
7343 EL_CHAR('B'), -1, -1
7346 Xalpha_c, TRUE, FALSE,
7347 EL_CHAR('C'), -1, -1
7350 Xalpha_d, TRUE, FALSE,
7351 EL_CHAR('D'), -1, -1
7354 Xalpha_e, TRUE, FALSE,
7355 EL_CHAR('E'), -1, -1
7358 Xalpha_f, TRUE, FALSE,
7359 EL_CHAR('F'), -1, -1
7362 Xalpha_g, TRUE, FALSE,
7363 EL_CHAR('G'), -1, -1
7366 Xalpha_h, TRUE, FALSE,
7367 EL_CHAR('H'), -1, -1
7370 Xalpha_i, TRUE, FALSE,
7371 EL_CHAR('I'), -1, -1
7374 Xalpha_j, TRUE, FALSE,
7375 EL_CHAR('J'), -1, -1
7378 Xalpha_k, TRUE, FALSE,
7379 EL_CHAR('K'), -1, -1
7382 Xalpha_l, TRUE, FALSE,
7383 EL_CHAR('L'), -1, -1
7386 Xalpha_m, TRUE, FALSE,
7387 EL_CHAR('M'), -1, -1
7390 Xalpha_n, TRUE, FALSE,
7391 EL_CHAR('N'), -1, -1
7394 Xalpha_o, TRUE, FALSE,
7395 EL_CHAR('O'), -1, -1
7398 Xalpha_p, TRUE, FALSE,
7399 EL_CHAR('P'), -1, -1
7402 Xalpha_q, TRUE, FALSE,
7403 EL_CHAR('Q'), -1, -1
7406 Xalpha_r, TRUE, FALSE,
7407 EL_CHAR('R'), -1, -1
7410 Xalpha_s, TRUE, FALSE,
7411 EL_CHAR('S'), -1, -1
7414 Xalpha_t, TRUE, FALSE,
7415 EL_CHAR('T'), -1, -1
7418 Xalpha_u, TRUE, FALSE,
7419 EL_CHAR('U'), -1, -1
7422 Xalpha_v, TRUE, FALSE,
7423 EL_CHAR('V'), -1, -1
7426 Xalpha_w, TRUE, FALSE,
7427 EL_CHAR('W'), -1, -1
7430 Xalpha_x, TRUE, FALSE,
7431 EL_CHAR('X'), -1, -1
7434 Xalpha_y, TRUE, FALSE,
7435 EL_CHAR('Y'), -1, -1
7438 Xalpha_z, TRUE, FALSE,
7439 EL_CHAR('Z'), -1, -1
7442 Xalpha_arrow_e, TRUE, FALSE,
7443 EL_CHAR('>'), -1, -1
7446 Xalpha_arrow_w, TRUE, FALSE,
7447 EL_CHAR('<'), -1, -1
7450 Xalpha_copyr, TRUE, FALSE,
7451 EL_CHAR('©'), -1, -1
7455 Xboom_bug, FALSE, FALSE,
7456 EL_BUG, ACTION_EXPLODING, -1
7459 Xboom_bomb, FALSE, FALSE,
7460 EL_BOMB, ACTION_EXPLODING, -1
7463 Xboom_android, FALSE, FALSE,
7464 EL_EMC_ANDROID, ACTION_OTHER, -1
7467 Xboom_1, FALSE, FALSE,
7468 EL_DEFAULT, ACTION_EXPLODING, -1
7471 Xboom_2, FALSE, FALSE,
7472 EL_DEFAULT, ACTION_EXPLODING, -1
7475 Znormal, FALSE, FALSE,
7479 Zdynamite, FALSE, FALSE,
7483 Zplayer, FALSE, FALSE,
7487 ZBORDER, FALSE, FALSE,
7497 static struct Mapping_EM_to_RND_player
7506 em_player_mapping_list[] =
7510 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
7514 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
7518 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
7522 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
7526 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
7530 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
7534 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
7538 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
7542 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
7546 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
7550 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
7554 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
7558 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
7562 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
7566 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
7570 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
7574 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
7578 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
7582 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
7586 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
7590 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
7594 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
7598 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
7602 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
7606 EL_PLAYER_1, ACTION_DEFAULT, -1,
7610 EL_PLAYER_2, ACTION_DEFAULT, -1,
7614 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
7618 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
7622 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
7626 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
7630 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
7634 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
7638 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
7642 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
7646 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
7650 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
7654 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
7658 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
7662 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
7666 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
7670 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
7674 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
7678 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
7682 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
7686 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
7690 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
7694 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
7698 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
7702 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
7706 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
7710 EL_PLAYER_3, ACTION_DEFAULT, -1,
7714 EL_PLAYER_4, ACTION_DEFAULT, -1,
7723 int map_element_RND_to_EM(int element_rnd)
7725 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
7726 static boolean mapping_initialized = FALSE;
7728 if (!mapping_initialized)
7732 /* return "Xalpha_quest" for all undefined elements in mapping array */
7733 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
7734 mapping_RND_to_EM[i] = Xalpha_quest;
7736 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7737 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
7738 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
7739 em_object_mapping_list[i].element_em;
7741 mapping_initialized = TRUE;
7744 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
7745 return mapping_RND_to_EM[element_rnd];
7747 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
7752 int map_element_EM_to_RND(int element_em)
7754 static unsigned short mapping_EM_to_RND[TILE_MAX];
7755 static boolean mapping_initialized = FALSE;
7757 if (!mapping_initialized)
7761 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
7762 for (i = 0; i < TILE_MAX; i++)
7763 mapping_EM_to_RND[i] = EL_UNKNOWN;
7765 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7766 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
7767 em_object_mapping_list[i].element_rnd;
7769 mapping_initialized = TRUE;
7772 if (element_em >= 0 && element_em < TILE_MAX)
7773 return mapping_EM_to_RND[element_em];
7775 Error(ERR_WARN, "invalid EM level element %d", element_em);
7780 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
7782 struct LevelInfo_EM *level_em = level->native_em_level;
7783 struct LEVEL *lev = level_em->lev;
7786 for (i = 0; i < TILE_MAX; i++)
7787 lev->android_array[i] = Xblank;
7789 for (i = 0; i < level->num_android_clone_elements; i++)
7791 int element_rnd = level->android_clone_element[i];
7792 int element_em = map_element_RND_to_EM(element_rnd);
7794 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
7795 if (em_object_mapping_list[j].element_rnd == element_rnd)
7796 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
7800 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
7802 struct LevelInfo_EM *level_em = level->native_em_level;
7803 struct LEVEL *lev = level_em->lev;
7806 level->num_android_clone_elements = 0;
7808 for (i = 0; i < TILE_MAX; i++)
7810 int element_em = lev->android_array[i];
7812 boolean element_found = FALSE;
7814 if (element_em == Xblank)
7817 element_rnd = map_element_EM_to_RND(element_em);
7819 for (j = 0; j < level->num_android_clone_elements; j++)
7820 if (level->android_clone_element[j] == element_rnd)
7821 element_found = TRUE;
7825 level->android_clone_element[level->num_android_clone_elements++] =
7828 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
7833 if (level->num_android_clone_elements == 0)
7835 level->num_android_clone_elements = 1;
7836 level->android_clone_element[0] = EL_EMPTY;
7840 int map_direction_RND_to_EM(int direction)
7842 return (direction == MV_UP ? 0 :
7843 direction == MV_RIGHT ? 1 :
7844 direction == MV_DOWN ? 2 :
7845 direction == MV_LEFT ? 3 :
7849 int map_direction_EM_to_RND(int direction)
7851 return (direction == 0 ? MV_UP :
7852 direction == 1 ? MV_RIGHT :
7853 direction == 2 ? MV_DOWN :
7854 direction == 3 ? MV_LEFT :
7858 int map_element_RND_to_SP(int element_rnd)
7860 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
7862 if (element_rnd >= EL_SP_START &&
7863 element_rnd <= EL_SP_END)
7864 element_sp = element_rnd - EL_SP_START;
7865 else if (element_rnd == EL_EMPTY_SPACE)
7867 else if (element_rnd == EL_INVISIBLE_WALL)
7873 int map_element_SP_to_RND(int element_sp)
7875 int element_rnd = EL_UNKNOWN;
7877 if (element_sp >= 0x00 &&
7879 element_rnd = EL_SP_START + element_sp;
7880 else if (element_sp == 0x28)
7881 element_rnd = EL_INVISIBLE_WALL;
7886 int map_action_SP_to_RND(int action_sp)
7890 case actActive: return ACTION_ACTIVE;
7891 case actImpact: return ACTION_IMPACT;
7892 case actExploding: return ACTION_EXPLODING;
7893 case actDigging: return ACTION_DIGGING;
7894 case actSnapping: return ACTION_SNAPPING;
7895 case actCollecting: return ACTION_COLLECTING;
7896 case actPassing: return ACTION_PASSING;
7897 case actPushing: return ACTION_PUSHING;
7898 case actDropping: return ACTION_DROPPING;
7900 default: return ACTION_DEFAULT;
7904 int get_next_element(int element)
7908 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
7909 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
7910 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
7911 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
7912 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
7913 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
7914 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
7915 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
7916 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
7917 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
7918 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
7920 default: return element;
7925 int el_act_dir2img(int element, int action, int direction)
7927 element = GFX_ELEMENT(element);
7929 if (direction == MV_NONE)
7930 return element_info[element].graphic[action];
7932 direction = MV_DIR_TO_BIT(direction);
7934 return element_info[element].direction_graphic[action][direction];
7937 int el_act_dir2img(int element, int action, int direction)
7939 element = GFX_ELEMENT(element);
7940 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7942 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7943 return element_info[element].direction_graphic[action][direction];
7948 static int el_act_dir2crm(int element, int action, int direction)
7950 element = GFX_ELEMENT(element);
7952 if (direction == MV_NONE)
7953 return element_info[element].crumbled[action];
7955 direction = MV_DIR_TO_BIT(direction);
7957 return element_info[element].direction_crumbled[action][direction];
7960 static int el_act_dir2crm(int element, int action, int direction)
7962 element = GFX_ELEMENT(element);
7963 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
7965 /* direction_graphic[][] == graphic[] for undefined direction graphics */
7966 return element_info[element].direction_crumbled[action][direction];
7970 int el_act2img(int element, int action)
7972 element = GFX_ELEMENT(element);
7974 return element_info[element].graphic[action];
7977 int el_act2crm(int element, int action)
7979 element = GFX_ELEMENT(element);
7981 return element_info[element].crumbled[action];
7984 int el_dir2img(int element, int direction)
7986 element = GFX_ELEMENT(element);
7988 return el_act_dir2img(element, ACTION_DEFAULT, direction);
7991 int el2baseimg(int element)
7993 return element_info[element].graphic[ACTION_DEFAULT];
7996 int el2img(int element)
7998 element = GFX_ELEMENT(element);
8000 return element_info[element].graphic[ACTION_DEFAULT];
8003 int el2edimg(int element)
8005 element = GFX_ELEMENT(element);
8007 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
8010 int el2preimg(int element)
8012 element = GFX_ELEMENT(element);
8014 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
8017 int el2panelimg(int element)
8019 element = GFX_ELEMENT(element);
8021 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
8024 int font2baseimg(int font_nr)
8026 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
8029 int getBeltNrFromBeltElement(int element)
8031 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
8032 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
8033 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
8036 int getBeltNrFromBeltActiveElement(int element)
8038 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
8039 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
8040 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
8043 int getBeltNrFromBeltSwitchElement(int element)
8045 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
8046 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
8047 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
8050 int getBeltDirNrFromBeltElement(int element)
8052 static int belt_base_element[4] =
8054 EL_CONVEYOR_BELT_1_LEFT,
8055 EL_CONVEYOR_BELT_2_LEFT,
8056 EL_CONVEYOR_BELT_3_LEFT,
8057 EL_CONVEYOR_BELT_4_LEFT
8060 int belt_nr = getBeltNrFromBeltElement(element);
8061 int belt_dir_nr = element - belt_base_element[belt_nr];
8063 return (belt_dir_nr % 3);
8066 int getBeltDirNrFromBeltSwitchElement(int element)
8068 static int belt_base_element[4] =
8070 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8071 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8072 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8073 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8076 int belt_nr = getBeltNrFromBeltSwitchElement(element);
8077 int belt_dir_nr = element - belt_base_element[belt_nr];
8079 return (belt_dir_nr % 3);
8082 int getBeltDirFromBeltElement(int element)
8084 static int belt_move_dir[3] =
8091 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
8093 return belt_move_dir[belt_dir_nr];
8096 int getBeltDirFromBeltSwitchElement(int element)
8098 static int belt_move_dir[3] =
8105 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
8107 return belt_move_dir[belt_dir_nr];
8110 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8112 static int belt_base_element[4] =
8114 EL_CONVEYOR_BELT_1_LEFT,
8115 EL_CONVEYOR_BELT_2_LEFT,
8116 EL_CONVEYOR_BELT_3_LEFT,
8117 EL_CONVEYOR_BELT_4_LEFT
8120 return belt_base_element[belt_nr] + belt_dir_nr;
8123 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8125 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8127 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8130 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
8132 static int belt_base_element[4] =
8134 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
8135 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
8136 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
8137 EL_CONVEYOR_BELT_4_SWITCH_LEFT
8140 return belt_base_element[belt_nr] + belt_dir_nr;
8143 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
8145 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
8147 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
8150 int getNumActivePlayers_EM()
8152 int num_players = 0;
8158 for (i = 0; i < MAX_PLAYERS; i++)
8159 if (tape.player_participates[i])
8165 int getGameFrameDelay_EM(int native_em_game_frame_delay)
8167 int game_frame_delay_value;
8169 game_frame_delay_value =
8170 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
8171 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
8174 if (tape.playing && tape.warp_forward && !tape.pausing)
8175 game_frame_delay_value = 0;
8177 return game_frame_delay_value;
8180 unsigned int InitRND(int seed)
8182 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
8183 return InitEngineRandom_EM(seed);
8184 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
8185 return InitEngineRandom_SP(seed);
8187 return InitEngineRandom_RND(seed);
8191 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
8192 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
8195 inline static int get_effective_element_EM(int tile, int frame_em)
8197 int element = object_mapping[tile].element_rnd;
8198 int action = object_mapping[tile].action;
8199 boolean is_backside = object_mapping[tile].is_backside;
8200 boolean action_removing = (action == ACTION_DIGGING ||
8201 action == ACTION_SNAPPING ||
8202 action == ACTION_COLLECTING);
8208 case Yacid_splash_eB:
8209 case Yacid_splash_wB:
8210 return (frame_em > 5 ? EL_EMPTY : element);
8214 case Ydiamond_stone:
8215 // if (!game.use_native_emc_graphics_engine)
8223 else /* frame_em == 7 */
8227 case Yacid_splash_eB:
8228 case Yacid_splash_wB:
8231 case Yemerald_stone:
8234 case Ydiamond_stone:
8238 case Xdrip_stretchB:
8257 case Xsand_stonein_1:
8258 case Xsand_stonein_2:
8259 case Xsand_stonein_3:
8260 case Xsand_stonein_4:
8264 return (is_backside || action_removing ? EL_EMPTY : element);
8269 inline static boolean check_linear_animation_EM(int tile)
8273 case Xsand_stonesand_1:
8274 case Xsand_stonesand_quickout_1:
8275 case Xsand_sandstone_1:
8276 case Xsand_stonein_1:
8277 case Xsand_stoneout_1:
8297 case Yacid_splash_eB:
8298 case Yacid_splash_wB:
8299 case Yemerald_stone:
8307 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
8308 boolean has_crumbled_graphics,
8309 int crumbled, int sync_frame)
8311 /* if element can be crumbled, but certain action graphics are just empty
8312 space (like instantly snapping sand to empty space in 1 frame), do not
8313 treat these empty space graphics as crumbled graphics in EMC engine */
8314 if (crumbled == IMG_EMPTY_SPACE)
8315 has_crumbled_graphics = FALSE;
8317 if (has_crumbled_graphics)
8319 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8320 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8321 g_crumbled->anim_delay,
8322 g_crumbled->anim_mode,
8323 g_crumbled->anim_start_frame,
8326 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8327 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8329 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
8331 g_em->has_crumbled_graphics = TRUE;
8335 g_em->crumbled_bitmap = NULL;
8336 g_em->crumbled_src_x = 0;
8337 g_em->crumbled_src_y = 0;
8338 g_em->crumbled_border_size = 0;
8340 g_em->has_crumbled_graphics = FALSE;
8344 void ResetGfxAnimation_EM(int x, int y, int tile)
8349 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
8350 int tile, int frame_em, int x, int y)
8352 int action = object_mapping[tile].action;
8354 int direction = object_mapping[tile].direction;
8355 int effective_element = get_effective_element_EM(tile, frame_em);
8356 int graphic = (direction == MV_NONE ?
8357 el_act2img(effective_element, action) :
8358 el_act_dir2img(effective_element, action, direction));
8359 struct GraphicInfo *g = &graphic_info[graphic];
8362 boolean action_removing = (action == ACTION_DIGGING ||
8363 action == ACTION_SNAPPING ||
8364 action == ACTION_COLLECTING);
8365 boolean action_moving = (action == ACTION_FALLING ||
8366 action == ACTION_MOVING ||
8367 action == ACTION_PUSHING ||
8368 action == ACTION_EATING ||
8369 action == ACTION_FILLING ||
8370 action == ACTION_EMPTYING);
8371 boolean action_falling = (action == ACTION_FALLING ||
8372 action == ACTION_FILLING ||
8373 action == ACTION_EMPTYING);
8375 /* special case: graphic uses "2nd movement tile" and has defined
8376 7 frames for movement animation (or less) => use default graphic
8377 for last (8th) frame which ends the movement animation */
8378 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8380 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
8381 graphic = (direction == MV_NONE ?
8382 el_act2img(effective_element, action) :
8383 el_act_dir2img(effective_element, action, direction));
8385 g = &graphic_info[graphic];
8389 if (tile == Xsand_stonesand_1 ||
8390 tile == Xsand_stonesand_2 ||
8391 tile == Xsand_stonesand_3 ||
8392 tile == Xsand_stonesand_4)
8393 printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
8397 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
8401 // printf("::: resetting... [%d]\n", tile);
8404 if (action_removing || check_linear_animation_EM(tile))
8406 GfxFrame[x][y] = frame_em;
8408 // printf("::: resetting... [%d]\n", tile);
8411 else if (action_moving)
8413 boolean is_backside = object_mapping[tile].is_backside;
8417 int direction = object_mapping[tile].direction;
8418 int move_dir = (action_falling ? MV_DOWN : direction);
8423 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
8424 if (g->double_movement && frame_em == 0)
8428 // printf("::: resetting... [%d]\n", tile);
8432 if (move_dir == MV_LEFT)
8433 GfxFrame[x - 1][y] = GfxFrame[x][y];
8434 else if (move_dir == MV_RIGHT)
8435 GfxFrame[x + 1][y] = GfxFrame[x][y];
8436 else if (move_dir == MV_UP)
8437 GfxFrame[x][y - 1] = GfxFrame[x][y];
8438 else if (move_dir == MV_DOWN)
8439 GfxFrame[x][y + 1] = GfxFrame[x][y];
8446 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
8447 if (tile == Xsand_stonesand_quickout_1 ||
8448 tile == Xsand_stonesand_quickout_2)
8453 if (tile == Xsand_stonesand_1 ||
8454 tile == Xsand_stonesand_2 ||
8455 tile == Xsand_stonesand_3 ||
8456 tile == Xsand_stonesand_4)
8457 printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
8461 if (graphic_info[graphic].anim_global_sync)
8462 sync_frame = FrameCounter;
8463 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8464 sync_frame = GfxFrame[x][y];
8466 sync_frame = 0; /* playfield border (pseudo steel) */
8468 SetRandomAnimationValue(x, y);
8470 int frame = getAnimationFrame(g->anim_frames,
8473 g->anim_start_frame,
8476 g_em->unique_identifier =
8477 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
8481 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
8482 int tile, int frame_em, int x, int y)
8484 int action = object_mapping[tile].action;
8485 int direction = object_mapping[tile].direction;
8486 boolean is_backside = object_mapping[tile].is_backside;
8487 int effective_element = get_effective_element_EM(tile, frame_em);
8489 int effective_action = action;
8491 int effective_action = (frame_em < 7 ? action : ACTION_DEFAULT);
8493 int graphic = (direction == MV_NONE ?
8494 el_act2img(effective_element, effective_action) :
8495 el_act_dir2img(effective_element, effective_action,
8497 int crumbled = (direction == MV_NONE ?
8498 el_act2crm(effective_element, effective_action) :
8499 el_act_dir2crm(effective_element, effective_action,
8501 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8502 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8503 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8504 struct GraphicInfo *g = &graphic_info[graphic];
8506 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8510 /* special case: graphic uses "2nd movement tile" and has defined
8511 7 frames for movement animation (or less) => use default graphic
8512 for last (8th) frame which ends the movement animation */
8513 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
8515 effective_action = ACTION_DEFAULT;
8516 graphic = (direction == MV_NONE ?
8517 el_act2img(effective_element, effective_action) :
8518 el_act_dir2img(effective_element, effective_action,
8520 crumbled = (direction == MV_NONE ?
8521 el_act2crm(effective_element, effective_action) :
8522 el_act_dir2crm(effective_element, effective_action,
8525 g = &graphic_info[graphic];
8535 if (frame_em == 0) /* reset animation frame for certain elements */
8537 if (check_linear_animation_EM(tile))
8542 if (graphic_info[graphic].anim_global_sync)
8543 sync_frame = FrameCounter;
8544 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
8545 sync_frame = GfxFrame[x][y];
8547 sync_frame = 0; /* playfield border (pseudo steel) */
8549 SetRandomAnimationValue(x, y);
8554 int xxx_sync_frame = (i == Xdrip_stretch ? 7 :
8555 i == Xdrip_stretchB ? 7 :
8556 i == Ydrip_s2 ? j + 8 :
8557 i == Ydrip_s2B ? j + 8 :
8566 i == Xfake_acid_1 ? 0 :
8567 i == Xfake_acid_2 ? 10 :
8568 i == Xfake_acid_3 ? 20 :
8569 i == Xfake_acid_4 ? 30 :
8570 i == Xfake_acid_5 ? 40 :
8571 i == Xfake_acid_6 ? 50 :
8572 i == Xfake_acid_7 ? 60 :
8573 i == Xfake_acid_8 ? 70 :
8575 i == Xball_2B ? j + 8 :
8576 i == Yball_eat ? j + 1 :
8577 i == Ykey_1_eat ? j + 1 :
8578 i == Ykey_2_eat ? j + 1 :
8579 i == Ykey_3_eat ? j + 1 :
8580 i == Ykey_4_eat ? j + 1 :
8581 i == Ykey_5_eat ? j + 1 :
8582 i == Ykey_6_eat ? j + 1 :
8583 i == Ykey_7_eat ? j + 1 :
8584 i == Ykey_8_eat ? j + 1 :
8585 i == Ylenses_eat ? j + 1 :
8586 i == Ymagnify_eat ? j + 1 :
8587 i == Ygrass_eat ? j + 1 :
8588 i == Ydirt_eat ? j + 1 :
8589 i == Xamoeba_1 ? 0 :
8590 i == Xamoeba_2 ? 1 :
8591 i == Xamoeba_3 ? 2 :
8592 i == Xamoeba_4 ? 3 :
8593 i == Xamoeba_5 ? 0 :
8594 i == Xamoeba_6 ? 1 :
8595 i == Xamoeba_7 ? 2 :
8596 i == Xamoeba_8 ? 3 :
8597 i == Xexit_2 ? j + 8 :
8598 i == Xexit_3 ? j + 16 :
8599 i == Xdynamite_1 ? 0 :
8600 i == Xdynamite_2 ? 8 :
8601 i == Xdynamite_3 ? 16 :
8602 i == Xdynamite_4 ? 24 :
8603 i == Xsand_stonein_1 ? j + 1 :
8604 i == Xsand_stonein_2 ? j + 9 :
8605 i == Xsand_stonein_3 ? j + 17 :
8606 i == Xsand_stonein_4 ? j + 25 :
8607 i == Xsand_stoneout_1 && j == 0 ? 0 :
8608 i == Xsand_stoneout_1 && j == 1 ? 0 :
8609 i == Xsand_stoneout_1 && j == 2 ? 1 :
8610 i == Xsand_stoneout_1 && j == 3 ? 2 :
8611 i == Xsand_stoneout_1 && j == 4 ? 2 :
8612 i == Xsand_stoneout_1 && j == 5 ? 3 :
8613 i == Xsand_stoneout_1 && j == 6 ? 4 :
8614 i == Xsand_stoneout_1 && j == 7 ? 4 :
8615 i == Xsand_stoneout_2 && j == 0 ? 5 :
8616 i == Xsand_stoneout_2 && j == 1 ? 6 :
8617 i == Xsand_stoneout_2 && j == 2 ? 7 :
8618 i == Xsand_stoneout_2 && j == 3 ? 8 :
8619 i == Xsand_stoneout_2 && j == 4 ? 9 :
8620 i == Xsand_stoneout_2 && j == 5 ? 11 :
8621 i == Xsand_stoneout_2 && j == 6 ? 13 :
8622 i == Xsand_stoneout_2 && j == 7 ? 15 :
8623 i == Xboom_bug && j == 1 ? 2 :
8624 i == Xboom_bug && j == 2 ? 2 :
8625 i == Xboom_bug && j == 3 ? 4 :
8626 i == Xboom_bug && j == 4 ? 4 :
8627 i == Xboom_bug && j == 5 ? 2 :
8628 i == Xboom_bug && j == 6 ? 2 :
8629 i == Xboom_bug && j == 7 ? 0 :
8630 i == Xboom_bomb && j == 1 ? 2 :
8631 i == Xboom_bomb && j == 2 ? 2 :
8632 i == Xboom_bomb && j == 3 ? 4 :
8633 i == Xboom_bomb && j == 4 ? 4 :
8634 i == Xboom_bomb && j == 5 ? 2 :
8635 i == Xboom_bomb && j == 6 ? 2 :
8636 i == Xboom_bomb && j == 7 ? 0 :
8637 i == Xboom_android && j == 7 ? 6 :
8638 i == Xboom_1 && j == 1 ? 2 :
8639 i == Xboom_1 && j == 2 ? 2 :
8640 i == Xboom_1 && j == 3 ? 4 :
8641 i == Xboom_1 && j == 4 ? 4 :
8642 i == Xboom_1 && j == 5 ? 6 :
8643 i == Xboom_1 && j == 6 ? 6 :
8644 i == Xboom_1 && j == 7 ? 8 :
8645 i == Xboom_2 && j == 0 ? 8 :
8646 i == Xboom_2 && j == 1 ? 8 :
8647 i == Xboom_2 && j == 2 ? 10 :
8648 i == Xboom_2 && j == 3 ? 10 :
8649 i == Xboom_2 && j == 4 ? 10 :
8650 i == Xboom_2 && j == 5 ? 12 :
8651 i == Xboom_2 && j == 6 ? 12 :
8652 i == Xboom_2 && j == 7 ? 12 :
8654 special_animation && j == 4 ? 3 :
8655 effective_action != action ? 0 :
8661 int xxx_effective_action;
8662 int xxx_has_action_graphics;
8665 int element = object_mapping[i].element_rnd;
8666 int action = object_mapping[i].action;
8667 int direction = object_mapping[i].direction;
8668 boolean is_backside = object_mapping[i].is_backside;
8670 boolean action_removing = (action == ACTION_DIGGING ||
8671 action == ACTION_SNAPPING ||
8672 action == ACTION_COLLECTING);
8674 boolean action_exploding = ((action == ACTION_EXPLODING ||
8675 action == ACTION_SMASHED_BY_ROCK ||
8676 action == ACTION_SMASHED_BY_SPRING) &&
8677 element != EL_DIAMOND);
8678 boolean action_active = (action == ACTION_ACTIVE);
8679 boolean action_other = (action == ACTION_OTHER);
8683 int effective_element = get_effective_element_EM(i, j);
8685 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
8686 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
8688 i == Xdrip_stretch ? element :
8689 i == Xdrip_stretchB ? element :
8690 i == Ydrip_s1 ? element :
8691 i == Ydrip_s1B ? element :
8692 i == Xball_1B ? element :
8693 i == Xball_2 ? element :
8694 i == Xball_2B ? element :
8695 i == Yball_eat ? element :
8696 i == Ykey_1_eat ? element :
8697 i == Ykey_2_eat ? element :
8698 i == Ykey_3_eat ? element :
8699 i == Ykey_4_eat ? element :
8700 i == Ykey_5_eat ? element :
8701 i == Ykey_6_eat ? element :
8702 i == Ykey_7_eat ? element :
8703 i == Ykey_8_eat ? element :
8704 i == Ylenses_eat ? element :
8705 i == Ymagnify_eat ? element :
8706 i == Ygrass_eat ? element :
8707 i == Ydirt_eat ? element :
8708 i == Yemerald_stone ? EL_EMERALD :
8709 i == Ydiamond_stone ? EL_ROCK :
8710 i == Xsand_stonein_1 ? element :
8711 i == Xsand_stonein_2 ? element :
8712 i == Xsand_stonein_3 ? element :
8713 i == Xsand_stonein_4 ? element :
8714 is_backside ? EL_EMPTY :
8715 action_removing ? EL_EMPTY :
8718 int effective_action = (j < 7 ? action :
8719 i == Xdrip_stretch ? action :
8720 i == Xdrip_stretchB ? action :
8721 i == Ydrip_s1 ? action :
8722 i == Ydrip_s1B ? action :
8723 i == Xball_1B ? action :
8724 i == Xball_2 ? action :
8725 i == Xball_2B ? action :
8726 i == Yball_eat ? action :
8727 i == Ykey_1_eat ? action :
8728 i == Ykey_2_eat ? action :
8729 i == Ykey_3_eat ? action :
8730 i == Ykey_4_eat ? action :
8731 i == Ykey_5_eat ? action :
8732 i == Ykey_6_eat ? action :
8733 i == Ykey_7_eat ? action :
8734 i == Ykey_8_eat ? action :
8735 i == Ylenses_eat ? action :
8736 i == Ymagnify_eat ? action :
8737 i == Ygrass_eat ? action :
8738 i == Ydirt_eat ? action :
8739 i == Xsand_stonein_1 ? action :
8740 i == Xsand_stonein_2 ? action :
8741 i == Xsand_stonein_3 ? action :
8742 i == Xsand_stonein_4 ? action :
8743 i == Xsand_stoneout_1 ? action :
8744 i == Xsand_stoneout_2 ? action :
8745 i == Xboom_android ? ACTION_EXPLODING :
8746 action_exploding ? ACTION_EXPLODING :
8747 action_active ? action :
8748 action_other ? action :
8750 int graphic = (el_act_dir2img(effective_element, effective_action,
8752 int crumbled = (el_act_dir2crm(effective_element, effective_action,
8754 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
8755 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
8756 boolean has_action_graphics = (graphic != base_graphic);
8757 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
8758 struct GraphicInfo *g = &graphic_info[graphic];
8760 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
8762 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
8765 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
8766 boolean special_animation = (action != ACTION_DEFAULT &&
8767 g->anim_frames == 3 &&
8768 g->anim_delay == 2 &&
8769 g->anim_mode & ANIM_LINEAR);
8770 xxx_sync_frame = (i == Xdrip_stretch ? 7 :
8771 i == Xdrip_stretchB ? 7 :
8772 i == Ydrip_s2 ? j + 8 :
8773 i == Ydrip_s2B ? j + 8 :
8782 i == Xfake_acid_1 ? 0 :
8783 i == Xfake_acid_2 ? 10 :
8784 i == Xfake_acid_3 ? 20 :
8785 i == Xfake_acid_4 ? 30 :
8786 i == Xfake_acid_5 ? 40 :
8787 i == Xfake_acid_6 ? 50 :
8788 i == Xfake_acid_7 ? 60 :
8789 i == Xfake_acid_8 ? 70 :
8791 i == Xball_2B ? j + 8 :
8792 i == Yball_eat ? j + 1 :
8793 i == Ykey_1_eat ? j + 1 :
8794 i == Ykey_2_eat ? j + 1 :
8795 i == Ykey_3_eat ? j + 1 :
8796 i == Ykey_4_eat ? j + 1 :
8797 i == Ykey_5_eat ? j + 1 :
8798 i == Ykey_6_eat ? j + 1 :
8799 i == Ykey_7_eat ? j + 1 :
8800 i == Ykey_8_eat ? j + 1 :
8801 i == Ylenses_eat ? j + 1 :
8802 i == Ymagnify_eat ? j + 1 :
8803 i == Ygrass_eat ? j + 1 :
8804 i == Ydirt_eat ? j + 1 :
8805 i == Xamoeba_1 ? 0 :
8806 i == Xamoeba_2 ? 1 :
8807 i == Xamoeba_3 ? 2 :
8808 i == Xamoeba_4 ? 3 :
8809 i == Xamoeba_5 ? 0 :
8810 i == Xamoeba_6 ? 1 :
8811 i == Xamoeba_7 ? 2 :
8812 i == Xamoeba_8 ? 3 :
8813 i == Xexit_2 ? j + 8 :
8814 i == Xexit_3 ? j + 16 :
8815 i == Xdynamite_1 ? 0 :
8816 i == Xdynamite_2 ? 8 :
8817 i == Xdynamite_3 ? 16 :
8818 i == Xdynamite_4 ? 24 :
8819 i == Xsand_stonein_1 ? j + 1 :
8820 i == Xsand_stonein_2 ? j + 9 :
8821 i == Xsand_stonein_3 ? j + 17 :
8822 i == Xsand_stonein_4 ? j + 25 :
8823 i == Xsand_stoneout_1 && j == 0 ? 0 :
8824 i == Xsand_stoneout_1 && j == 1 ? 0 :
8825 i == Xsand_stoneout_1 && j == 2 ? 1 :
8826 i == Xsand_stoneout_1 && j == 3 ? 2 :
8827 i == Xsand_stoneout_1 && j == 4 ? 2 :
8828 i == Xsand_stoneout_1 && j == 5 ? 3 :
8829 i == Xsand_stoneout_1 && j == 6 ? 4 :
8830 i == Xsand_stoneout_1 && j == 7 ? 4 :
8831 i == Xsand_stoneout_2 && j == 0 ? 5 :
8832 i == Xsand_stoneout_2 && j == 1 ? 6 :
8833 i == Xsand_stoneout_2 && j == 2 ? 7 :
8834 i == Xsand_stoneout_2 && j == 3 ? 8 :
8835 i == Xsand_stoneout_2 && j == 4 ? 9 :
8836 i == Xsand_stoneout_2 && j == 5 ? 11 :
8837 i == Xsand_stoneout_2 && j == 6 ? 13 :
8838 i == Xsand_stoneout_2 && j == 7 ? 15 :
8839 i == Xboom_bug && j == 1 ? 2 :
8840 i == Xboom_bug && j == 2 ? 2 :
8841 i == Xboom_bug && j == 3 ? 4 :
8842 i == Xboom_bug && j == 4 ? 4 :
8843 i == Xboom_bug && j == 5 ? 2 :
8844 i == Xboom_bug && j == 6 ? 2 :
8845 i == Xboom_bug && j == 7 ? 0 :
8846 i == Xboom_bomb && j == 1 ? 2 :
8847 i == Xboom_bomb && j == 2 ? 2 :
8848 i == Xboom_bomb && j == 3 ? 4 :
8849 i == Xboom_bomb && j == 4 ? 4 :
8850 i == Xboom_bomb && j == 5 ? 2 :
8851 i == Xboom_bomb && j == 6 ? 2 :
8852 i == Xboom_bomb && j == 7 ? 0 :
8853 i == Xboom_android && j == 7 ? 6 :
8854 i == Xboom_1 && j == 1 ? 2 :
8855 i == Xboom_1 && j == 2 ? 2 :
8856 i == Xboom_1 && j == 3 ? 4 :
8857 i == Xboom_1 && j == 4 ? 4 :
8858 i == Xboom_1 && j == 5 ? 6 :
8859 i == Xboom_1 && j == 6 ? 6 :
8860 i == Xboom_1 && j == 7 ? 8 :
8861 i == Xboom_2 && j == 0 ? 8 :
8862 i == Xboom_2 && j == 1 ? 8 :
8863 i == Xboom_2 && j == 2 ? 10 :
8864 i == Xboom_2 && j == 3 ? 10 :
8865 i == Xboom_2 && j == 4 ? 10 :
8866 i == Xboom_2 && j == 5 ? 12 :
8867 i == Xboom_2 && j == 6 ? 12 :
8868 i == Xboom_2 && j == 7 ? 12 :
8869 special_animation && j == 4 ? 3 :
8870 effective_action != action ? 0 :
8873 xxx_effective_action = effective_action;
8874 xxx_has_action_graphics = has_action_graphics;
8879 int frame = getAnimationFrame(g->anim_frames,
8882 g->anim_start_frame,
8896 int old_src_x = g_em->src_x;
8897 int old_src_y = g_em->src_y;
8901 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
8902 g->double_movement && is_backside);
8904 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
8905 &g_em->src_x, &g_em->src_y, FALSE);
8910 if (tile == Ydiamond_stone)
8911 printf("::: stone smashing diamond... %d: %d, %d, %d, %d, %d -> %d [%d, %d, %d, %d, %d, %d] [%d]\n",
8916 g->anim_start_frame,
8919 g_em->src_x, g_em->src_y,
8920 g_em->src_offset_x, g_em->src_offset_y,
8921 g_em->dst_offset_x, g_em->dst_offset_y,
8933 if (graphic == IMG_BUG_MOVING_RIGHT)
8934 printf("::: %d, %d, %d: %d, %d [%d, %d -> %d, %d]\n", graphic, x, y,
8935 g->double_movement, is_backside,
8936 old_src_x, old_src_y, g_em->src_x, g_em->src_y);
8944 g_em->src_offset_x = 0;
8945 g_em->src_offset_y = 0;
8946 g_em->dst_offset_x = 0;
8947 g_em->dst_offset_y = 0;
8948 g_em->width = TILEX;
8949 g_em->height = TILEY;
8951 g_em->preserve_background = FALSE;
8954 /* (updating the "crumbled" graphic definitions is probably not really needed,
8955 as animations for crumbled graphics can't be longer than one EMC cycle) */
8957 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
8962 g_em->crumbled_bitmap = NULL;
8963 g_em->crumbled_src_x = 0;
8964 g_em->crumbled_src_y = 0;
8966 g_em->has_crumbled_graphics = FALSE;
8968 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
8970 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
8971 g_crumbled->anim_delay,
8972 g_crumbled->anim_mode,
8973 g_crumbled->anim_start_frame,
8976 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
8977 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
8979 g_em->has_crumbled_graphics = TRUE;
8985 int effective_action = xxx_effective_action;
8986 int has_action_graphics = xxx_has_action_graphics;
8988 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
8989 effective_action == ACTION_MOVING ||
8990 effective_action == ACTION_PUSHING ||
8991 effective_action == ACTION_EATING)) ||
8992 (!has_action_graphics && (effective_action == ACTION_FILLING ||
8993 effective_action == ACTION_EMPTYING)))
8996 (effective_action == ACTION_FALLING ||
8997 effective_action == ACTION_FILLING ||
8998 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
8999 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9000 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9001 int num_steps = (i == Ydrip_s1 ? 16 :
9002 i == Ydrip_s1B ? 16 :
9003 i == Ydrip_s2 ? 16 :
9004 i == Ydrip_s2B ? 16 :
9005 i == Xsand_stonein_1 ? 32 :
9006 i == Xsand_stonein_2 ? 32 :
9007 i == Xsand_stonein_3 ? 32 :
9008 i == Xsand_stonein_4 ? 32 :
9009 i == Xsand_stoneout_1 ? 16 :
9010 i == Xsand_stoneout_2 ? 16 : 8);
9011 int cx = ABS(dx) * (TILEX / num_steps);
9012 int cy = ABS(dy) * (TILEY / num_steps);
9013 int step_frame = (i == Ydrip_s2 ? j + 8 :
9014 i == Ydrip_s2B ? j + 8 :
9015 i == Xsand_stonein_2 ? j + 8 :
9016 i == Xsand_stonein_3 ? j + 16 :
9017 i == Xsand_stonein_4 ? j + 24 :
9018 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9019 int step = (is_backside ? step_frame : num_steps - step_frame);
9021 if (is_backside) /* tile where movement starts */
9023 if (dx < 0 || dy < 0)
9025 g_em->src_offset_x = cx * step;
9026 g_em->src_offset_y = cy * step;
9030 g_em->dst_offset_x = cx * step;
9031 g_em->dst_offset_y = cy * step;
9034 else /* tile where movement ends */
9036 if (dx < 0 || dy < 0)
9038 g_em->dst_offset_x = cx * step;
9039 g_em->dst_offset_y = cy * step;
9043 g_em->src_offset_x = cx * step;
9044 g_em->src_offset_y = cy * step;
9048 g_em->width = TILEX - cx * step;
9049 g_em->height = TILEY - cy * step;
9052 /* create unique graphic identifier to decide if tile must be redrawn */
9053 /* bit 31 - 16 (16 bit): EM style graphic
9054 bit 15 - 12 ( 4 bit): EM style frame
9055 bit 11 - 6 ( 6 bit): graphic width
9056 bit 5 - 0 ( 6 bit): graphic height */
9057 g_em->unique_identifier =
9058 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
9064 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
9065 int player_nr, int anim, int frame_em)
9067 int element = player_mapping[player_nr][anim].element_rnd;
9068 int action = player_mapping[player_nr][anim].action;
9069 int direction = player_mapping[player_nr][anim].direction;
9070 int graphic = (direction == MV_NONE ?
9071 el_act2img(element, action) :
9072 el_act_dir2img(element, action, direction));
9073 struct GraphicInfo *g = &graphic_info[graphic];
9076 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
9078 stored_player[player_nr].StepFrame = frame_em;
9080 sync_frame = stored_player[player_nr].Frame;
9082 int frame = getAnimationFrame(g->anim_frames,
9085 g->anim_start_frame,
9088 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
9089 &g_em->src_x, &g_em->src_y, FALSE);
9092 printf("::: %d: %d, %d [%d]\n",
9094 stored_player[player_nr].Frame,
9095 stored_player[player_nr].StepFrame,
9100 void InitGraphicInfo_EM(void)
9103 struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
9104 struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
9109 int num_em_gfx_errors = 0;
9111 if (graphic_info_em_object[0][0].bitmap == NULL)
9113 /* EM graphics not yet initialized in em_open_all() */
9118 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
9121 /* always start with reliable default values */
9122 for (i = 0; i < TILE_MAX; i++)
9124 object_mapping[i].element_rnd = EL_UNKNOWN;
9125 object_mapping[i].is_backside = FALSE;
9126 object_mapping[i].action = ACTION_DEFAULT;
9127 object_mapping[i].direction = MV_NONE;
9130 /* always start with reliable default values */
9131 for (p = 0; p < MAX_PLAYERS; p++)
9133 for (i = 0; i < SPR_MAX; i++)
9135 player_mapping[p][i].element_rnd = EL_UNKNOWN;
9136 player_mapping[p][i].action = ACTION_DEFAULT;
9137 player_mapping[p][i].direction = MV_NONE;
9141 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
9143 int e = em_object_mapping_list[i].element_em;
9145 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
9146 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
9148 if (em_object_mapping_list[i].action != -1)
9149 object_mapping[e].action = em_object_mapping_list[i].action;
9151 if (em_object_mapping_list[i].direction != -1)
9152 object_mapping[e].direction =
9153 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
9156 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
9158 int a = em_player_mapping_list[i].action_em;
9159 int p = em_player_mapping_list[i].player_nr;
9161 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
9163 if (em_player_mapping_list[i].action != -1)
9164 player_mapping[p][a].action = em_player_mapping_list[i].action;
9166 if (em_player_mapping_list[i].direction != -1)
9167 player_mapping[p][a].direction =
9168 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
9171 for (i = 0; i < TILE_MAX; i++)
9173 int element = object_mapping[i].element_rnd;
9174 int action = object_mapping[i].action;
9175 int direction = object_mapping[i].direction;
9176 boolean is_backside = object_mapping[i].is_backside;
9178 boolean action_removing = (action == ACTION_DIGGING ||
9179 action == ACTION_SNAPPING ||
9180 action == ACTION_COLLECTING);
9182 boolean action_exploding = ((action == ACTION_EXPLODING ||
9183 action == ACTION_SMASHED_BY_ROCK ||
9184 action == ACTION_SMASHED_BY_SPRING) &&
9185 element != EL_DIAMOND);
9186 boolean action_active = (action == ACTION_ACTIVE);
9187 boolean action_other = (action == ACTION_OTHER);
9189 for (j = 0; j < 8; j++)
9192 int effective_element = get_effective_element_EM(i, j);
9194 int effective_element = (j > 5 && i == Yacid_splash_eB ? EL_EMPTY :
9195 j > 5 && i == Yacid_splash_wB ? EL_EMPTY :
9197 i == Xdrip_stretch ? element :
9198 i == Xdrip_stretchB ? element :
9199 i == Ydrip_s1 ? element :
9200 i == Ydrip_s1B ? element :
9201 i == Xball_1B ? element :
9202 i == Xball_2 ? element :
9203 i == Xball_2B ? element :
9204 i == Yball_eat ? element :
9205 i == Ykey_1_eat ? element :
9206 i == Ykey_2_eat ? element :
9207 i == Ykey_3_eat ? element :
9208 i == Ykey_4_eat ? element :
9209 i == Ykey_5_eat ? element :
9210 i == Ykey_6_eat ? element :
9211 i == Ykey_7_eat ? element :
9212 i == Ykey_8_eat ? element :
9213 i == Ylenses_eat ? element :
9214 i == Ymagnify_eat ? element :
9215 i == Ygrass_eat ? element :
9216 i == Ydirt_eat ? element :
9217 i == Yemerald_stone ? EL_EMERALD :
9218 i == Ydiamond_stone ? EL_ROCK :
9219 i == Xsand_stonein_1 ? element :
9220 i == Xsand_stonein_2 ? element :
9221 i == Xsand_stonein_3 ? element :
9222 i == Xsand_stonein_4 ? element :
9223 is_backside ? EL_EMPTY :
9224 action_removing ? EL_EMPTY :
9227 int effective_action = (j < 7 ? action :
9228 i == Xdrip_stretch ? action :
9229 i == Xdrip_stretchB ? action :
9230 i == Ydrip_s1 ? action :
9231 i == Ydrip_s1B ? action :
9232 i == Xball_1B ? action :
9233 i == Xball_2 ? action :
9234 i == Xball_2B ? action :
9235 i == Yball_eat ? action :
9236 i == Ykey_1_eat ? action :
9237 i == Ykey_2_eat ? action :
9238 i == Ykey_3_eat ? action :
9239 i == Ykey_4_eat ? action :
9240 i == Ykey_5_eat ? action :
9241 i == Ykey_6_eat ? action :
9242 i == Ykey_7_eat ? action :
9243 i == Ykey_8_eat ? action :
9244 i == Ylenses_eat ? action :
9245 i == Ymagnify_eat ? action :
9246 i == Ygrass_eat ? action :
9247 i == Ydirt_eat ? action :
9248 i == Xsand_stonein_1 ? action :
9249 i == Xsand_stonein_2 ? action :
9250 i == Xsand_stonein_3 ? action :
9251 i == Xsand_stonein_4 ? action :
9252 i == Xsand_stoneout_1 ? action :
9253 i == Xsand_stoneout_2 ? action :
9254 i == Xboom_android ? ACTION_EXPLODING :
9255 action_exploding ? ACTION_EXPLODING :
9256 action_active ? action :
9257 action_other ? action :
9259 int graphic = (el_act_dir2img(effective_element, effective_action,
9261 int crumbled = (el_act_dir2crm(effective_element, effective_action,
9263 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
9264 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
9265 boolean has_action_graphics = (graphic != base_graphic);
9266 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
9267 struct GraphicInfo *g = &graphic_info[graphic];
9269 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
9271 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9274 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
9275 boolean special_animation = (action != ACTION_DEFAULT &&
9276 g->anim_frames == 3 &&
9277 g->anim_delay == 2 &&
9278 g->anim_mode & ANIM_LINEAR);
9279 int sync_frame = (i == Xdrip_stretch ? 7 :
9280 i == Xdrip_stretchB ? 7 :
9281 i == Ydrip_s2 ? j + 8 :
9282 i == Ydrip_s2B ? j + 8 :
9291 i == Xfake_acid_1 ? 0 :
9292 i == Xfake_acid_2 ? 10 :
9293 i == Xfake_acid_3 ? 20 :
9294 i == Xfake_acid_4 ? 30 :
9295 i == Xfake_acid_5 ? 40 :
9296 i == Xfake_acid_6 ? 50 :
9297 i == Xfake_acid_7 ? 60 :
9298 i == Xfake_acid_8 ? 70 :
9300 i == Xball_2B ? j + 8 :
9301 i == Yball_eat ? j + 1 :
9302 i == Ykey_1_eat ? j + 1 :
9303 i == Ykey_2_eat ? j + 1 :
9304 i == Ykey_3_eat ? j + 1 :
9305 i == Ykey_4_eat ? j + 1 :
9306 i == Ykey_5_eat ? j + 1 :
9307 i == Ykey_6_eat ? j + 1 :
9308 i == Ykey_7_eat ? j + 1 :
9309 i == Ykey_8_eat ? j + 1 :
9310 i == Ylenses_eat ? j + 1 :
9311 i == Ymagnify_eat ? j + 1 :
9312 i == Ygrass_eat ? j + 1 :
9313 i == Ydirt_eat ? j + 1 :
9314 i == Xamoeba_1 ? 0 :
9315 i == Xamoeba_2 ? 1 :
9316 i == Xamoeba_3 ? 2 :
9317 i == Xamoeba_4 ? 3 :
9318 i == Xamoeba_5 ? 0 :
9319 i == Xamoeba_6 ? 1 :
9320 i == Xamoeba_7 ? 2 :
9321 i == Xamoeba_8 ? 3 :
9322 i == Xexit_2 ? j + 8 :
9323 i == Xexit_3 ? j + 16 :
9324 i == Xdynamite_1 ? 0 :
9325 i == Xdynamite_2 ? 8 :
9326 i == Xdynamite_3 ? 16 :
9327 i == Xdynamite_4 ? 24 :
9328 i == Xsand_stonein_1 ? j + 1 :
9329 i == Xsand_stonein_2 ? j + 9 :
9330 i == Xsand_stonein_3 ? j + 17 :
9331 i == Xsand_stonein_4 ? j + 25 :
9332 i == Xsand_stoneout_1 && j == 0 ? 0 :
9333 i == Xsand_stoneout_1 && j == 1 ? 0 :
9334 i == Xsand_stoneout_1 && j == 2 ? 1 :
9335 i == Xsand_stoneout_1 && j == 3 ? 2 :
9336 i == Xsand_stoneout_1 && j == 4 ? 2 :
9337 i == Xsand_stoneout_1 && j == 5 ? 3 :
9338 i == Xsand_stoneout_1 && j == 6 ? 4 :
9339 i == Xsand_stoneout_1 && j == 7 ? 4 :
9340 i == Xsand_stoneout_2 && j == 0 ? 5 :
9341 i == Xsand_stoneout_2 && j == 1 ? 6 :
9342 i == Xsand_stoneout_2 && j == 2 ? 7 :
9343 i == Xsand_stoneout_2 && j == 3 ? 8 :
9344 i == Xsand_stoneout_2 && j == 4 ? 9 :
9345 i == Xsand_stoneout_2 && j == 5 ? 11 :
9346 i == Xsand_stoneout_2 && j == 6 ? 13 :
9347 i == Xsand_stoneout_2 && j == 7 ? 15 :
9348 i == Xboom_bug && j == 1 ? 2 :
9349 i == Xboom_bug && j == 2 ? 2 :
9350 i == Xboom_bug && j == 3 ? 4 :
9351 i == Xboom_bug && j == 4 ? 4 :
9352 i == Xboom_bug && j == 5 ? 2 :
9353 i == Xboom_bug && j == 6 ? 2 :
9354 i == Xboom_bug && j == 7 ? 0 :
9355 i == Xboom_bomb && j == 1 ? 2 :
9356 i == Xboom_bomb && j == 2 ? 2 :
9357 i == Xboom_bomb && j == 3 ? 4 :
9358 i == Xboom_bomb && j == 4 ? 4 :
9359 i == Xboom_bomb && j == 5 ? 2 :
9360 i == Xboom_bomb && j == 6 ? 2 :
9361 i == Xboom_bomb && j == 7 ? 0 :
9362 i == Xboom_android && j == 7 ? 6 :
9363 i == Xboom_1 && j == 1 ? 2 :
9364 i == Xboom_1 && j == 2 ? 2 :
9365 i == Xboom_1 && j == 3 ? 4 :
9366 i == Xboom_1 && j == 4 ? 4 :
9367 i == Xboom_1 && j == 5 ? 6 :
9368 i == Xboom_1 && j == 6 ? 6 :
9369 i == Xboom_1 && j == 7 ? 8 :
9370 i == Xboom_2 && j == 0 ? 8 :
9371 i == Xboom_2 && j == 1 ? 8 :
9372 i == Xboom_2 && j == 2 ? 10 :
9373 i == Xboom_2 && j == 3 ? 10 :
9374 i == Xboom_2 && j == 4 ? 10 :
9375 i == Xboom_2 && j == 5 ? 12 :
9376 i == Xboom_2 && j == 6 ? 12 :
9377 i == Xboom_2 && j == 7 ? 12 :
9378 special_animation && j == 4 ? 3 :
9379 effective_action != action ? 0 :
9383 Bitmap *debug_bitmap = g_em->bitmap;
9384 int debug_src_x = g_em->src_x;
9385 int debug_src_y = g_em->src_y;
9388 int frame = getAnimationFrame(g->anim_frames,
9391 g->anim_start_frame,
9394 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
9395 g->double_movement && is_backside);
9397 g_em->bitmap = src_bitmap;
9398 g_em->src_x = src_x;
9399 g_em->src_y = src_y;
9400 g_em->src_offset_x = 0;
9401 g_em->src_offset_y = 0;
9402 g_em->dst_offset_x = 0;
9403 g_em->dst_offset_y = 0;
9404 g_em->width = TILEX;
9405 g_em->height = TILEY;
9407 g_em->preserve_background = FALSE;
9410 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
9415 g_em->crumbled_bitmap = NULL;
9416 g_em->crumbled_src_x = 0;
9417 g_em->crumbled_src_y = 0;
9418 g_em->crumbled_border_size = 0;
9420 g_em->has_crumbled_graphics = FALSE;
9423 if (has_crumbled_graphics && crumbled == IMG_EMPTY_SPACE)
9424 printf("::: empty crumbled: %d [%s], %d, %d\n",
9425 effective_element, element_info[effective_element].token_name,
9426 effective_action, direction);
9429 /* if element can be crumbled, but certain action graphics are just empty
9430 space (like instantly snapping sand to empty space in 1 frame), do not
9431 treat these empty space graphics as crumbled graphics in EMC engine */
9432 if (has_crumbled_graphics && crumbled != IMG_EMPTY_SPACE)
9434 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
9435 g_crumbled->anim_delay,
9436 g_crumbled->anim_mode,
9437 g_crumbled->anim_start_frame,
9440 getGraphicSource(crumbled, frame_crumbled, &src_bitmap, &src_x, &src_y);
9442 g_em->has_crumbled_graphics = TRUE;
9443 g_em->crumbled_bitmap = src_bitmap;
9444 g_em->crumbled_src_x = src_x;
9445 g_em->crumbled_src_y = src_y;
9446 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
9450 if (g_em == &graphic_info_em_object[207][0])
9451 printf("... %d, %d [%d, %d, %d, %d] [%d, %d, %d, %d, %d, %d => %d]\n",
9452 graphic_info_em_object[207][0].crumbled_src_x,
9453 graphic_info_em_object[207][0].crumbled_src_y,
9455 crumbled, frame, src_x, src_y,
9460 g->anim_start_frame,
9462 gfx.anim_random_frame,
9467 printf("::: EMC tile %d is crumbled\n", i);
9473 if (element == EL_ROCK &&
9474 effective_action == ACTION_FILLING)
9475 printf("::: has_action_graphics == %d\n", has_action_graphics);
9478 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
9479 effective_action == ACTION_MOVING ||
9480 effective_action == ACTION_PUSHING ||
9481 effective_action == ACTION_EATING)) ||
9482 (!has_action_graphics && (effective_action == ACTION_FILLING ||
9483 effective_action == ACTION_EMPTYING)))
9486 (effective_action == ACTION_FALLING ||
9487 effective_action == ACTION_FILLING ||
9488 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
9489 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
9490 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
9491 int num_steps = (i == Ydrip_s1 ? 16 :
9492 i == Ydrip_s1B ? 16 :
9493 i == Ydrip_s2 ? 16 :
9494 i == Ydrip_s2B ? 16 :
9495 i == Xsand_stonein_1 ? 32 :
9496 i == Xsand_stonein_2 ? 32 :
9497 i == Xsand_stonein_3 ? 32 :
9498 i == Xsand_stonein_4 ? 32 :
9499 i == Xsand_stoneout_1 ? 16 :
9500 i == Xsand_stoneout_2 ? 16 : 8);
9501 int cx = ABS(dx) * (TILEX / num_steps);
9502 int cy = ABS(dy) * (TILEY / num_steps);
9503 int step_frame = (i == Ydrip_s2 ? j + 8 :
9504 i == Ydrip_s2B ? j + 8 :
9505 i == Xsand_stonein_2 ? j + 8 :
9506 i == Xsand_stonein_3 ? j + 16 :
9507 i == Xsand_stonein_4 ? j + 24 :
9508 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
9509 int step = (is_backside ? step_frame : num_steps - step_frame);
9511 if (is_backside) /* tile where movement starts */
9513 if (dx < 0 || dy < 0)
9515 g_em->src_offset_x = cx * step;
9516 g_em->src_offset_y = cy * step;
9520 g_em->dst_offset_x = cx * step;
9521 g_em->dst_offset_y = cy * step;
9524 else /* tile where movement ends */
9526 if (dx < 0 || dy < 0)
9528 g_em->dst_offset_x = cx * step;
9529 g_em->dst_offset_y = cy * step;
9533 g_em->src_offset_x = cx * step;
9534 g_em->src_offset_y = cy * step;
9538 g_em->width = TILEX - cx * step;
9539 g_em->height = TILEY - cy * step;
9542 /* create unique graphic identifier to decide if tile must be redrawn */
9543 /* bit 31 - 16 (16 bit): EM style graphic
9544 bit 15 - 12 ( 4 bit): EM style frame
9545 bit 11 - 6 ( 6 bit): graphic width
9546 bit 5 - 0 ( 6 bit): graphic height */
9547 g_em->unique_identifier =
9548 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
9552 /* skip check for EMC elements not contained in original EMC artwork */
9553 if (element == EL_EMC_FAKE_ACID)
9556 if (g_em->bitmap != debug_bitmap ||
9557 g_em->src_x != debug_src_x ||
9558 g_em->src_y != debug_src_y ||
9559 g_em->src_offset_x != 0 ||
9560 g_em->src_offset_y != 0 ||
9561 g_em->dst_offset_x != 0 ||
9562 g_em->dst_offset_y != 0 ||
9563 g_em->width != TILEX ||
9564 g_em->height != TILEY)
9566 static int last_i = -1;
9574 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
9575 i, element, element_info[element].token_name,
9576 element_action_info[effective_action].suffix, direction);
9578 if (element != effective_element)
9579 printf(" [%d ('%s')]",
9581 element_info[effective_element].token_name);
9585 if (g_em->bitmap != debug_bitmap)
9586 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
9587 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
9589 if (g_em->src_x != debug_src_x ||
9590 g_em->src_y != debug_src_y)
9591 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
9592 j, (is_backside ? 'B' : 'F'),
9593 g_em->src_x, g_em->src_y,
9594 g_em->src_x / 32, g_em->src_y / 32,
9595 debug_src_x, debug_src_y,
9596 debug_src_x / 32, debug_src_y / 32);
9598 if (g_em->src_offset_x != 0 ||
9599 g_em->src_offset_y != 0 ||
9600 g_em->dst_offset_x != 0 ||
9601 g_em->dst_offset_y != 0)
9602 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
9604 g_em->src_offset_x, g_em->src_offset_y,
9605 g_em->dst_offset_x, g_em->dst_offset_y);
9607 if (g_em->width != TILEX ||
9608 g_em->height != TILEY)
9609 printf(" %d (%d): size %d,%d should be %d,%d\n",
9611 g_em->width, g_em->height, TILEX, TILEY);
9613 num_em_gfx_errors++;
9620 for (i = 0; i < TILE_MAX; i++)
9622 for (j = 0; j < 8; j++)
9624 int element = object_mapping[i].element_rnd;
9625 int action = object_mapping[i].action;
9626 int direction = object_mapping[i].direction;
9627 boolean is_backside = object_mapping[i].is_backside;
9628 int graphic_action = el_act_dir2img(element, action, direction);
9629 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
9631 if ((action == ACTION_SMASHED_BY_ROCK ||
9632 action == ACTION_SMASHED_BY_SPRING ||
9633 action == ACTION_EATING) &&
9634 graphic_action == graphic_default)
9636 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
9637 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
9638 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
9639 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
9642 /* no separate animation for "smashed by rock" -- use rock instead */
9643 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
9644 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
9646 g_em->bitmap = g_xx->bitmap;
9647 g_em->src_x = g_xx->src_x;
9648 g_em->src_y = g_xx->src_y;
9649 g_em->src_offset_x = g_xx->src_offset_x;
9650 g_em->src_offset_y = g_xx->src_offset_y;
9651 g_em->dst_offset_x = g_xx->dst_offset_x;
9652 g_em->dst_offset_y = g_xx->dst_offset_y;
9653 g_em->width = g_xx->width;
9654 g_em->height = g_xx->height;
9655 g_em->unique_identifier = g_xx->unique_identifier;
9658 g_em->preserve_background = TRUE;
9663 for (p = 0; p < MAX_PLAYERS; p++)
9665 for (i = 0; i < SPR_MAX; i++)
9667 int element = player_mapping[p][i].element_rnd;
9668 int action = player_mapping[p][i].action;
9669 int direction = player_mapping[p][i].direction;
9671 for (j = 0; j < 8; j++)
9673 int effective_element = element;
9674 int effective_action = action;
9675 int graphic = (direction == MV_NONE ?
9676 el_act2img(effective_element, effective_action) :
9677 el_act_dir2img(effective_element, effective_action,
9679 struct GraphicInfo *g = &graphic_info[graphic];
9680 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
9686 Bitmap *debug_bitmap = g_em->bitmap;
9687 int debug_src_x = g_em->src_x;
9688 int debug_src_y = g_em->src_y;
9691 int frame = getAnimationFrame(g->anim_frames,
9694 g->anim_start_frame,
9697 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
9699 g_em->bitmap = src_bitmap;
9700 g_em->src_x = src_x;
9701 g_em->src_y = src_y;
9702 g_em->src_offset_x = 0;
9703 g_em->src_offset_y = 0;
9704 g_em->dst_offset_x = 0;
9705 g_em->dst_offset_y = 0;
9706 g_em->width = TILEX;
9707 g_em->height = TILEY;
9711 /* skip check for EMC elements not contained in original EMC artwork */
9712 if (element == EL_PLAYER_3 ||
9713 element == EL_PLAYER_4)
9716 if (g_em->bitmap != debug_bitmap ||
9717 g_em->src_x != debug_src_x ||
9718 g_em->src_y != debug_src_y)
9720 static int last_i = -1;
9728 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
9729 p, i, element, element_info[element].token_name,
9730 element_action_info[effective_action].suffix, direction);
9732 if (element != effective_element)
9733 printf(" [%d ('%s')]",
9735 element_info[effective_element].token_name);
9739 if (g_em->bitmap != debug_bitmap)
9740 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
9741 j, (int)(g_em->bitmap), (int)(debug_bitmap));
9743 if (g_em->src_x != debug_src_x ||
9744 g_em->src_y != debug_src_y)
9745 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
9747 g_em->src_x, g_em->src_y,
9748 g_em->src_x / 32, g_em->src_y / 32,
9749 debug_src_x, debug_src_y,
9750 debug_src_x / 32, debug_src_y / 32);
9752 num_em_gfx_errors++;
9762 printf("::: [%d errors found]\n", num_em_gfx_errors);
9768 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
9769 boolean any_player_moving,
9770 boolean player_is_dropping)
9772 if (tape.single_step && tape.recording && !tape.pausing)
9775 boolean active_players = FALSE;
9778 for (i = 0; i < MAX_PLAYERS; i++)
9779 if (action[i] != JOY_NO_ACTION)
9780 active_players = TRUE;
9784 if (frame == 0 && !player_is_dropping)
9785 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9789 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
9790 boolean murphy_is_dropping)
9793 printf("::: waiting: %d, dropping: %d\n",
9794 murphy_is_waiting, murphy_is_dropping);
9797 if (tape.single_step && tape.recording && !tape.pausing)
9799 // if (murphy_is_waiting || murphy_is_dropping)
9800 if (murphy_is_waiting)
9803 printf("::: murphy is waiting -> pause mode\n");
9806 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
9811 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
9812 int graphic, int sync_frame, int x, int y)
9814 int frame = getGraphicAnimationFrame(graphic, sync_frame);
9816 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
9819 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
9821 return (IS_NEXT_FRAME(sync_frame, graphic));
9824 int getGraphicInfo_Delay(int graphic)
9826 return graphic_info[graphic].anim_delay;
9829 void PlayMenuSoundExt(int sound)
9831 if (sound == SND_UNDEFINED)
9834 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9835 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9838 if (IS_LOOP_SOUND(sound))
9839 PlaySoundLoop(sound);
9844 void PlayMenuSound()
9846 PlayMenuSoundExt(menu.sound[game_status]);
9849 void PlayMenuSoundStereo(int sound, int stereo_position)
9851 if (sound == SND_UNDEFINED)
9854 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9855 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9858 if (IS_LOOP_SOUND(sound))
9859 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
9861 PlaySoundStereo(sound, stereo_position);
9864 void PlayMenuSoundIfLoopExt(int sound)
9866 if (sound == SND_UNDEFINED)
9869 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
9870 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
9873 if (IS_LOOP_SOUND(sound))
9874 PlaySoundLoop(sound);
9877 void PlayMenuSoundIfLoop()
9879 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
9882 void PlayMenuMusicExt(int music)
9884 if (music == MUS_UNDEFINED)
9887 if (!setup.sound_music)
9893 void PlayMenuMusic()
9895 PlayMenuMusicExt(menu.music[game_status]);
9898 void PlaySoundActivating()
9901 PlaySound(SND_MENU_ITEM_ACTIVATING);
9905 void PlaySoundSelecting()
9908 PlaySound(SND_MENU_ITEM_SELECTING);
9912 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
9914 boolean change_fullscreen = (setup.fullscreen !=
9915 video.fullscreen_enabled);
9916 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
9917 !strEqual(setup.fullscreen_mode,
9918 video.fullscreen_mode_current));
9919 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
9920 setup.window_scaling_percent !=
9921 video.window_scaling_percent);
9923 if (change_window_scaling_percent && video.fullscreen_enabled)
9926 if (!change_window_scaling_percent && !video.fullscreen_available)
9929 #if defined(TARGET_SDL2)
9930 if (change_window_scaling_percent)
9932 SDLSetWindowScaling(setup.window_scaling_percent);
9936 else if (change_fullscreen)
9938 SDLSetWindowFullscreen(setup.fullscreen);
9940 /* set setup value according to successfully changed fullscreen mode */
9941 setup.fullscreen = video.fullscreen_enabled;
9947 if (change_fullscreen ||
9948 change_fullscreen_mode ||
9949 change_window_scaling_percent)
9951 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
9953 /* save backbuffer content which gets lost when toggling fullscreen mode */
9954 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9956 if (change_fullscreen_mode)
9958 /* keep fullscreen, but change fullscreen mode (screen resolution) */
9959 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
9962 if (change_window_scaling_percent)
9964 /* keep window mode, but change window scaling */
9965 video.fullscreen_enabled = TRUE; /* force new window scaling */
9968 /* toggle fullscreen */
9969 ChangeVideoModeIfNeeded(setup.fullscreen);
9971 /* set setup value according to successfully changed fullscreen mode */
9972 setup.fullscreen = video.fullscreen_enabled;
9974 /* restore backbuffer content from temporary backbuffer backup bitmap */
9975 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9977 FreeBitmap(tmp_backbuffer);
9980 /* update visible window/screen */
9981 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
9983 redraw_mask = REDRAW_ALL;
9988 void ChangeViewportPropertiesIfNeeded()
9990 int *door_1_x = &DX;
9991 int *door_1_y = &DY;
9992 int *door_2_x = (game_status == GAME_MODE_EDITOR ? &EX : &VX);
9993 int *door_2_y = (game_status == GAME_MODE_EDITOR ? &EY : &VY);
9994 int gfx_game_mode = (game_status == GAME_MODE_PLAYING ||
9995 game_status == GAME_MODE_EDITOR ? game_status :
9997 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
9998 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
9999 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode];
10000 int border_size = vp_playfield->border_size;
10001 int new_sx = vp_playfield->x + border_size;
10002 int new_sy = vp_playfield->y + border_size;
10003 int new_sxsize = vp_playfield->width - 2 * border_size;
10004 int new_sysize = vp_playfield->height - 2 * border_size;
10005 int new_real_sx = vp_playfield->x;
10006 int new_real_sy = vp_playfield->y;
10007 int new_full_sxsize = vp_playfield->width;
10008 int new_full_sysize = vp_playfield->height;
10010 int new_tilesize_var = TILESIZE / (setup.small_game_graphics ? 2 : 1);
10011 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
10012 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
10013 int new_scr_fieldx = new_sxsize / tilesize;
10014 int new_scr_fieldy = new_sysize / tilesize;
10015 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
10016 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
10018 int new_scr_fieldx = (vp_playfield->width - 2 * border_size) / TILESIZE;
10019 int new_scr_fieldy = (vp_playfield->height - 2 * border_size) / TILESIZE;
10021 boolean init_gfx_buffers = FALSE;
10022 boolean init_video_buffer = FALSE;
10023 boolean init_gadgets_and_toons = FALSE;
10026 /* !!! TEST ONLY !!! */
10027 // InitGfxBuffers();
10031 if (viewport.window.width != WIN_XSIZE ||
10032 viewport.window.height != WIN_YSIZE)
10034 WIN_XSIZE = viewport.window.width;
10035 WIN_YSIZE = viewport.window.height;
10038 init_video_buffer = TRUE;
10039 init_gfx_buffers = TRUE;
10041 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
10045 SetDrawDeactivationMask(REDRAW_NONE);
10046 SetDrawBackgroundMask(REDRAW_FIELD);
10048 // RedrawBackground();
10052 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
10055 if (new_scr_fieldx != SCR_FIELDX ||
10056 new_scr_fieldy != SCR_FIELDY)
10058 /* this always toggles between MAIN and GAME when using small tile size */
10060 SCR_FIELDX = new_scr_fieldx;
10061 SCR_FIELDY = new_scr_fieldy;
10063 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
10067 if (new_tilesize_var != TILESIZE_VAR &&
10068 gfx_game_mode == GAME_MODE_PLAYING)
10070 /* doing this outside GAME_MODE_PLAYING would give wrong playfield size */
10072 TILESIZE_VAR = new_tilesize_var;
10074 init_gfx_buffers = TRUE;
10076 // printf("::: tilesize: init_gfx_buffers\n");
10080 if (new_sx != SX ||
10082 new_sxsize != SXSIZE ||
10083 new_sysize != SYSIZE ||
10084 new_real_sx != REAL_SX ||
10085 new_real_sy != REAL_SY ||
10086 new_full_sxsize != FULL_SXSIZE ||
10087 new_full_sysize != FULL_SYSIZE ||
10088 new_tilesize_var != TILESIZE_VAR ||
10089 vp_door_1->x != *door_1_x ||
10090 vp_door_1->y != *door_1_y ||
10091 vp_door_2->x != *door_2_x ||
10092 vp_door_2->y != *door_2_y)
10096 SXSIZE = new_sxsize;
10097 SYSIZE = new_sysize;
10098 REAL_SX = new_real_sx;
10099 REAL_SY = new_real_sy;
10100 FULL_SXSIZE = new_full_sxsize;
10101 FULL_SYSIZE = new_full_sysize;
10102 TILESIZE_VAR = new_tilesize_var;
10105 printf("::: %d, %d, %d [%d]\n",
10106 SCR_FIELDX, SCR_FIELDY, TILESIZE_VAR,
10107 setup.small_game_graphics);
10110 *door_1_x = vp_door_1->x;
10111 *door_1_y = vp_door_1->y;
10112 *door_2_x = vp_door_2->x;
10113 *door_2_y = vp_door_2->y;
10116 init_gfx_buffers = TRUE;
10118 // printf("::: viewports: init_gfx_buffers\n");
10123 if (gfx_game_mode == GAME_MODE_MAIN)
10126 init_gadgets_and_toons = TRUE;
10128 // printf("::: viewports: init_gadgets_and_toons\n");
10136 if (init_gfx_buffers)
10138 // printf("::: init_gfx_buffers\n");
10140 SCR_FIELDX = new_scr_fieldx_buffers;
10141 SCR_FIELDY = new_scr_fieldy_buffers;
10145 SCR_FIELDX = new_scr_fieldx;
10146 SCR_FIELDY = new_scr_fieldy;
10149 if (init_video_buffer)
10151 // printf("::: init_video_buffer\n");
10153 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
10155 SetDrawDeactivationMask(REDRAW_NONE);
10156 SetDrawBackgroundMask(REDRAW_FIELD);
10159 if (init_gadgets_and_toons)
10161 // printf("::: init_gadgets_and_toons\n");
10168 printf("::: %d, %d / %d, %d [%d]\n", VX, VY, EX, EY, game_status);