1 // ============================================================================
2 // Rocks'n'Diamonds - McDuffin Strikes Back!
3 // ----------------------------------------------------------------------------
4 // (c) 1995-2014 by Artsoft Entertainment
7 // http://www.artsoft.org/
8 // ----------------------------------------------------------------------------
10 // ============================================================================
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 /* constants for number of doors and door parts */
42 #define NUM_PANELS NUM_DOORS
43 // #define NUM_PANELS 0
44 #define MAX_PARTS_PER_DOOR 8
45 #define MAX_DOOR_PARTS (NUM_DOORS * MAX_PARTS_PER_DOOR + NUM_PANELS)
46 #define DOOR_PART_IS_PANEL(i) ((i) >= NUM_DOORS * MAX_PARTS_PER_DOOR)
49 struct DoorPartOrderInfo
55 static struct DoorPartOrderInfo door_part_order[MAX_DOOR_PARTS];
57 struct DoorPartControlInfo
61 struct DoorPartPosInfo *pos;
64 static struct DoorPartControlInfo door_part_controls[] =
68 IMG_DOOR_1_GFX_PART_1,
73 IMG_DOOR_1_GFX_PART_2,
78 IMG_DOOR_1_GFX_PART_3,
83 IMG_DOOR_1_GFX_PART_4,
88 IMG_DOOR_1_GFX_PART_5,
93 IMG_DOOR_1_GFX_PART_6,
98 IMG_DOOR_1_GFX_PART_7,
103 IMG_DOOR_1_GFX_PART_8,
109 IMG_DOOR_2_GFX_PART_1,
114 IMG_DOOR_2_GFX_PART_2,
119 IMG_DOOR_2_GFX_PART_3,
124 IMG_DOOR_2_GFX_PART_4,
129 IMG_DOOR_2_GFX_PART_5,
134 IMG_DOOR_2_GFX_PART_6,
139 IMG_DOOR_2_GFX_PART_7,
144 IMG_DOOR_2_GFX_PART_8,
150 IMG_BACKGROUND_PANEL,
167 /* forward declaration for internal use */
168 static void UnmapToolButtons();
169 static void HandleToolButtons(struct GadgetInfo *);
170 static int el_act_dir2crm(int, int, int);
171 static int el_act2crm(int, int);
173 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
174 static int request_gadget_id = -1;
176 static char *print_if_not_empty(int element)
178 static char *s = NULL;
179 char *token_name = element_info[element].token_name;
184 s = checked_malloc(strlen(token_name) + 10 + 1);
186 if (element != EL_EMPTY)
187 sprintf(s, "%d\t['%s']", element, token_name);
189 sprintf(s, "%d", element);
194 void DumpTile(int x, int y)
199 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
205 printf_line("-", 79);
206 printf("Field Info: SCREEN(%d, %d), LEVEL(%d, %d)\n", sx, sy, x, y);
207 printf_line("-", 79);
209 if (!IN_LEV_FIELD(x, y))
211 printf("(not in level field)\n");
217 printf(" Feld: %d\t['%s']\n", Feld[x][y],
218 element_info[Feld[x][y]].token_name);
219 printf(" Back: %s\n", print_if_not_empty(Back[x][y]));
220 printf(" Store: %s\n", print_if_not_empty(Store[x][y]));
221 printf(" Store2: %s\n", print_if_not_empty(Store2[x][y]));
222 printf(" StorePlayer: %s\n", print_if_not_empty(StorePlayer[x][y]));
223 printf(" MovPos: %d\n", MovPos[x][y]);
224 printf(" MovDir: %d\n", MovDir[x][y]);
225 printf(" MovDelay: %d\n", MovDelay[x][y]);
226 printf(" ChangeDelay: %d\n", ChangeDelay[x][y]);
227 printf(" CustomValue: %d\n", CustomValue[x][y]);
228 printf(" GfxElement: %d\n", GfxElement[x][y]);
229 printf(" GfxAction: %d\n", GfxAction[x][y]);
230 printf(" GfxFrame: %d\n", GfxFrame[x][y]);
234 void SetDrawtoField(int mode)
236 if (mode == DRAW_FIELDBUFFER)
242 BX2 = SCR_FIELDX + 1;
243 BY2 = SCR_FIELDY + 1;
245 drawto_field = fieldbuffer;
247 else /* DRAW_BACKBUFFER */
253 BX2 = SCR_FIELDX - 1;
254 BY2 = SCR_FIELDY - 1;
256 drawto_field = backbuffer;
260 static void RedrawPlayfield_RND()
262 if (game.envelope_active)
265 DrawLevel(REDRAW_ALL);
269 void RedrawPlayfield()
271 if (game_status != GAME_MODE_PLAYING)
274 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
275 RedrawPlayfield_EM(TRUE);
276 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
277 RedrawPlayfield_SP(TRUE);
278 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
279 RedrawPlayfield_RND();
281 BlitScreenToBitmap(backbuffer);
283 BlitBitmap(drawto, window, gfx.sx, gfx.sy, gfx.sxsize, gfx.sysize,
287 void DrawMaskedBorder_Rect(int x, int y, int width, int height)
289 Bitmap *bitmap = graphic_info[IMG_GLOBAL_BORDER].bitmap;
291 BlitBitmapMasked(bitmap, backbuffer, x, y, width, height, x, y);
294 void DrawMaskedBorder_FIELD()
296 if (global.border_status >= GAME_MODE_TITLE &&
297 global.border_status <= GAME_MODE_PLAYING &&
298 border.draw_masked[global.border_status])
299 DrawMaskedBorder_Rect(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
302 void DrawMaskedBorder_DOOR_1()
304 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
305 (global.border_status != GAME_MODE_EDITOR ||
306 border.draw_masked[GFX_SPECIAL_ARG_EDITOR]))
307 DrawMaskedBorder_Rect(DX, DY, DXSIZE, DYSIZE);
310 void DrawMaskedBorder_DOOR_2()
312 if (border.draw_masked[GFX_SPECIAL_ARG_DOOR] &&
313 global.border_status != GAME_MODE_EDITOR)
314 DrawMaskedBorder_Rect(VX, VY, VXSIZE, VYSIZE);
317 void DrawMaskedBorder_DOOR_3()
319 /* currently not available */
322 void DrawMaskedBorder_ALL()
324 DrawMaskedBorder_FIELD();
325 DrawMaskedBorder_DOOR_1();
326 DrawMaskedBorder_DOOR_2();
327 DrawMaskedBorder_DOOR_3();
330 void DrawMaskedBorder(int redraw_mask)
332 /* never draw masked screen borders on borderless screens */
333 if (effectiveGameStatus() == GAME_MODE_LOADING ||
334 effectiveGameStatus() == GAME_MODE_TITLE)
337 /* never draw masked screen borders when displaying request outside door */
338 if (effectiveGameStatus() == GAME_MODE_PSEUDO_DOOR &&
339 global.use_envelope_request)
342 if (redraw_mask & REDRAW_ALL)
343 DrawMaskedBorder_ALL();
346 if (redraw_mask & REDRAW_FIELD)
347 DrawMaskedBorder_FIELD();
348 if (redraw_mask & REDRAW_DOOR_1)
349 DrawMaskedBorder_DOOR_1();
350 if (redraw_mask & REDRAW_DOOR_2)
351 DrawMaskedBorder_DOOR_2();
352 if (redraw_mask & REDRAW_DOOR_3)
353 DrawMaskedBorder_DOOR_3();
357 static void BlitScreenToBitmap_RND(Bitmap *target_bitmap)
359 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
360 int fx = FX, fy = FY;
361 int full_lev_fieldx = lev_fieldx + (BorderElement != EL_EMPTY ? 2 : 0);
362 int full_lev_fieldy = lev_fieldy + (BorderElement != EL_EMPTY ? 2 : 0);
364 int dx = (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
365 int dy = (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
366 int dx_var = dx * TILESIZE_VAR / TILESIZE;
367 int dy_var = dy * TILESIZE_VAR / TILESIZE;
370 ffx = (scroll_x - SBX_Left) * TILEX_VAR + dx_var;
371 ffy = (scroll_y - SBY_Upper) * TILEY_VAR + dy_var;
373 if (EVEN(SCR_FIELDX))
375 if (ffx < SBX_Right * TILEX_VAR + TILEX_VAR / 2 + TILEX_VAR)
376 fx += dx_var - MIN(ffx, TILEX_VAR / 2) + TILEX_VAR;
378 fx += (dx_var > 0 ? TILEX_VAR : 0);
385 if (EVEN(SCR_FIELDY))
387 if (ffy < SBY_Lower * TILEY_VAR + TILEY_VAR / 2 + TILEY_VAR)
388 fy += dy_var - MIN(ffy, TILEY_VAR / 2) + TILEY_VAR;
390 fy += (dy_var > 0 ? TILEY_VAR : 0);
397 if (full_lev_fieldx <= SCR_FIELDX)
399 if (EVEN(SCR_FIELDX))
400 fx = 2 * TILEX_VAR - (ODD(lev_fieldx) ? TILEX_VAR / 2 : 0);
402 fx = 2 * TILEX_VAR - (EVEN(lev_fieldx) ? TILEX_VAR / 2 : 0);
405 if (full_lev_fieldy <= SCR_FIELDY)
407 if (EVEN(SCR_FIELDY))
408 fy = 2 * TILEY_VAR - (ODD(lev_fieldy) ? TILEY_VAR / 2 : 0);
410 fy = 2 * TILEY_VAR - (EVEN(lev_fieldy) ? TILEY_VAR / 2 : 0);
413 if (border.draw_masked[GAME_MODE_PLAYING])
415 if (buffer != backbuffer)
417 /* copy playfield buffer to backbuffer to add masked border */
418 BlitBitmap(buffer, backbuffer, fx, fy, SXSIZE, SYSIZE, SX, SY);
419 DrawMaskedBorder(REDRAW_FIELD);
422 BlitBitmap(backbuffer, target_bitmap,
423 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE,
428 BlitBitmap(buffer, target_bitmap, fx, fy, SXSIZE, SYSIZE, SX, SY);
432 void BlitScreenToBitmap(Bitmap *target_bitmap)
434 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
435 BlitScreenToBitmap_EM(target_bitmap);
436 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
437 BlitScreenToBitmap_SP(target_bitmap);
438 else if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
439 BlitScreenToBitmap_RND(target_bitmap);
444 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
447 /* !!! TEST ONLY !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
448 /* (force full redraw) */
449 if (game_status == GAME_MODE_PLAYING)
450 redraw_mask |= REDRAW_FIELD;
453 if (redraw_mask == REDRAW_NONE)
458 if (redraw_mask & REDRAW_ALL)
459 printf("[REDRAW_ALL]");
460 if (redraw_mask & REDRAW_FIELD)
461 printf("[REDRAW_FIELD]");
462 if (redraw_mask & REDRAW_DOOR_1)
463 printf("[REDRAW_DOOR_1]");
464 if (redraw_mask & REDRAW_DOOR_2)
465 printf("[REDRAW_DOOR_2]");
466 if (redraw_mask & REDRAW_FROM_BACKBUFFER)
467 printf("[REDRAW_FROM_BACKBUFFER]");
468 printf(" [%d]\n", FrameCounter);
471 if (global.fps_slowdown && game_status == GAME_MODE_PLAYING)
473 static boolean last_frame_skipped = FALSE;
474 boolean skip_even_when_not_scrolling = TRUE;
475 boolean just_scrolling = (ScreenMovDir != 0);
476 boolean verbose = FALSE;
478 if (global.fps_slowdown_factor > 1 &&
479 (FrameCounter % global.fps_slowdown_factor) &&
480 (just_scrolling || skip_even_when_not_scrolling))
482 redraw_mask &= ~REDRAW_MAIN;
484 last_frame_skipped = TRUE;
487 printf("FRAME SKIPPED\n");
491 if (last_frame_skipped)
492 redraw_mask |= REDRAW_FIELD;
494 last_frame_skipped = FALSE;
497 printf("frame not skipped\n");
501 /* synchronize X11 graphics at this point; if we would synchronize the
502 display immediately after the buffer switching (after the XFlush),
503 this could mean that we have to wait for the graphics to complete,
504 although we could go on doing calculations for the next frame */
508 /* never draw masked border to backbuffer when using playfield buffer */
509 if (game_status != GAME_MODE_PLAYING ||
510 redraw_mask & REDRAW_FROM_BACKBUFFER ||
511 buffer == backbuffer)
512 DrawMaskedBorder(redraw_mask);
514 DrawMaskedBorder(redraw_mask & REDRAW_DOORS);
516 if (redraw_mask & REDRAW_ALL)
518 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
520 redraw_mask = REDRAW_NONE;
523 if (redraw_mask & REDRAW_FIELD)
525 if (game_status != GAME_MODE_PLAYING ||
526 redraw_mask & REDRAW_FROM_BACKBUFFER)
528 BlitBitmap(backbuffer, window,
529 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
533 BlitScreenToBitmap_RND(window);
536 redraw_mask &= ~REDRAW_MAIN;
539 if (redraw_mask & REDRAW_DOORS)
541 if (redraw_mask & REDRAW_DOOR_1)
542 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
544 if (redraw_mask & REDRAW_DOOR_2)
545 BlitBitmap(backbuffer, window, VX, VY, VXSIZE, VYSIZE, VX, VY);
547 if (redraw_mask & REDRAW_DOOR_3)
548 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
550 redraw_mask &= ~REDRAW_DOORS;
553 if (redraw_mask & REDRAW_MICROLEVEL)
555 BlitBitmap(backbuffer, window, SX, SY + 10 * TILEY, SXSIZE, 7 * TILEY,
556 SX, SY + 10 * TILEY);
558 redraw_mask &= ~REDRAW_MICROLEVEL;
561 if (redraw_mask & REDRAW_FPS) /* display frames per second */
566 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
567 if (!global.fps_slowdown)
570 sprintf(text, "%04.1f fps%s", global.frames_per_second, info1);
572 DrawTextExt(window, SX + SXSIZE + SX, 0, text, FONT_TEXT_2, BLIT_OPAQUE);
575 redraw_mask = REDRAW_NONE;
578 static void FadeCrossSaveBackbuffer()
580 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
583 static void FadeExt(int fade_mask, int fade_mode, int fade_type)
585 static int fade_type_skip = FADE_TYPE_NONE;
586 void (*draw_border_function)(void) = NULL;
587 Bitmap *bitmap = (fade_mode & FADE_TYPE_TRANSFORM ? bitmap_db_cross : NULL);
588 int x, y, width, height;
589 int fade_delay, post_delay;
591 if (fade_type == FADE_TYPE_FADE_OUT)
593 if (fade_type_skip != FADE_TYPE_NONE)
595 /* skip all fade operations until specified fade operation */
596 if (fade_type & fade_type_skip)
597 fade_type_skip = FADE_TYPE_NONE;
602 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
604 FadeCrossSaveBackbuffer();
610 redraw_mask |= fade_mask;
612 if (fade_type == FADE_TYPE_SKIP)
614 fade_type_skip = fade_mode;
619 fade_delay = fading.fade_delay;
620 post_delay = (fade_mode == FADE_MODE_FADE_OUT ? fading.post_delay : 0);
622 if (fade_type_skip != FADE_TYPE_NONE)
624 /* skip all fade operations until specified fade operation */
625 if (fade_type & fade_type_skip)
626 fade_type_skip = FADE_TYPE_NONE;
631 if (global.autoplay_leveldir)
636 if (fade_mask == REDRAW_FIELD)
641 height = FULL_SYSIZE;
643 if (border.draw_masked_when_fading)
644 draw_border_function = DrawMaskedBorder_FIELD; /* update when fading */
646 DrawMaskedBorder_FIELD(); /* draw once */
648 else /* REDRAW_ALL */
656 if (!setup.fade_screens ||
658 fading.fade_mode == FADE_MODE_NONE)
660 if (fade_mode == FADE_MODE_FADE_OUT)
663 BlitBitmap(backbuffer, window, x, y, width, height, x, y);
665 redraw_mask &= ~fade_mask;
670 FadeRectangle(bitmap, x, y, width, height, fade_mode, fade_delay, post_delay,
671 draw_border_function);
673 redraw_mask &= ~fade_mask;
676 void FadeIn(int fade_mask)
678 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
679 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_IN);
681 FadeExt(fade_mask, FADE_MODE_FADE_IN, FADE_TYPE_FADE_IN);
684 void FadeOut(int fade_mask)
686 if (fading.fade_mode & FADE_TYPE_TRANSFORM)
687 FadeExt(fade_mask, fading.fade_mode, FADE_TYPE_FADE_OUT);
689 FadeExt(fade_mask, FADE_MODE_FADE_OUT, FADE_TYPE_FADE_OUT);
691 global.border_status = game_status;
694 static void FadeSetLeaveNext(struct TitleFadingInfo fading_leave, boolean set)
696 static struct TitleFadingInfo fading_leave_stored;
699 fading_leave_stored = fading_leave;
701 fading = fading_leave_stored;
704 void FadeSetEnterMenu()
706 fading = menu.enter_menu;
708 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
711 void FadeSetLeaveMenu()
713 fading = menu.leave_menu;
715 FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
718 void FadeSetEnterScreen()
720 fading = menu.enter_screen[game_status];
722 FadeSetLeaveNext(menu.leave_screen[game_status], TRUE); /* store */
725 void FadeSetNextScreen()
727 fading = menu.next_screen;
729 // (do not overwrite fade mode set by FadeSetEnterScreen)
730 // FadeSetLeaveNext(fading, TRUE); /* (keep same fade mode) */
733 void FadeSetLeaveScreen()
735 FadeSetLeaveNext(menu.leave_screen[game_status], FALSE); /* recall */
738 void FadeSetFromType(int type)
740 if (type & TYPE_ENTER_SCREEN)
741 FadeSetEnterScreen();
742 else if (type & TYPE_ENTER)
744 else if (type & TYPE_LEAVE)
748 void FadeSetDisabled()
750 static struct TitleFadingInfo fading_none = { FADE_MODE_NONE, -1, -1, -1 };
752 fading = fading_none;
755 void FadeSkipNextFadeIn()
757 FadeExt(0, FADE_MODE_SKIP_FADE_IN, FADE_TYPE_SKIP);
760 void FadeSkipNextFadeOut()
762 FadeExt(0, FADE_MODE_SKIP_FADE_OUT, FADE_TYPE_SKIP);
765 void SetWindowBackgroundImageIfDefined(int graphic)
767 if (graphic_info[graphic].bitmap)
768 SetWindowBackgroundBitmap(graphic_info[graphic].bitmap);
771 void SetMainBackgroundImageIfDefined(int graphic)
773 if (graphic_info[graphic].bitmap)
774 SetMainBackgroundBitmap(graphic_info[graphic].bitmap);
777 void SetDoorBackgroundImageIfDefined(int graphic)
779 if (graphic_info[graphic].bitmap)
780 SetDoorBackgroundBitmap(graphic_info[graphic].bitmap);
783 void SetWindowBackgroundImage(int graphic)
785 SetWindowBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
786 graphic_info[graphic].bitmap ?
787 graphic_info[graphic].bitmap :
788 graphic_info[IMG_BACKGROUND].bitmap);
791 void SetMainBackgroundImage(int graphic)
793 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
794 graphic_info[graphic].bitmap ?
795 graphic_info[graphic].bitmap :
796 graphic_info[IMG_BACKGROUND].bitmap);
799 void SetDoorBackgroundImage(int graphic)
801 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
802 graphic_info[graphic].bitmap ?
803 graphic_info[graphic].bitmap :
804 graphic_info[IMG_BACKGROUND].bitmap);
807 void SetPanelBackground()
809 struct GraphicInfo *gfx = &graphic_info[IMG_BACKGROUND_PANEL];
811 BlitBitmapTiled(gfx->bitmap, bitmap_db_panel, gfx->src_x, gfx->src_y,
812 gfx->width, gfx->height, 0, 0, DXSIZE, DYSIZE);
814 SetDoorBackgroundBitmap(bitmap_db_panel);
817 void DrawBackground(int x, int y, int width, int height)
819 /* "drawto" might still point to playfield buffer here (hall of fame) */
820 ClearRectangleOnBackground(backbuffer, x, y, width, height);
822 if (IN_GFX_FIELD_FULL(x, y))
823 redraw_mask |= REDRAW_FIELD;
824 else if (IN_GFX_DOOR_1(x, y))
825 redraw_mask |= REDRAW_DOOR_1;
826 else if (IN_GFX_DOOR_2(x, y))
827 redraw_mask |= REDRAW_DOOR_2;
828 else if (IN_GFX_DOOR_3(x, y))
829 redraw_mask |= REDRAW_DOOR_3;
832 void DrawBackgroundForFont(int x, int y, int width, int height, int font_nr)
834 struct FontBitmapInfo *font = getFontBitmapInfo(font_nr);
836 if (font->bitmap == NULL)
839 DrawBackground(x, y, width, height);
842 void DrawBackgroundForGraphic(int x, int y, int width, int height, int graphic)
844 struct GraphicInfo *g = &graphic_info[graphic];
846 if (g->bitmap == NULL)
849 DrawBackground(x, y, width, height);
854 /* !!! "drawto" might still point to playfield buffer here (see above) !!! */
855 /* (when entering hall of fame after playing) */
856 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
858 /* !!! maybe this should be done before clearing the background !!! */
859 if (game_status == GAME_MODE_PLAYING)
861 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
862 SetDrawtoField(DRAW_FIELDBUFFER);
865 SetDrawtoField(DRAW_BACKBUFFER);
868 void MarkTileDirty(int x, int y)
870 redraw_mask |= REDRAW_FIELD;
873 void SetBorderElement()
877 BorderElement = EL_EMPTY;
879 for (y = 0; y < lev_fieldy && BorderElement == EL_EMPTY; y++)
881 for (x = 0; x < lev_fieldx; x++)
883 if (!IS_INDESTRUCTIBLE(Feld[x][y]))
884 BorderElement = EL_STEELWALL;
886 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
892 void FloodFillLevel(int from_x, int from_y, int fill_element,
893 short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY],
894 int max_fieldx, int max_fieldy)
898 static int check[4][2] = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } };
899 static int safety = 0;
901 /* check if starting field still has the desired content */
902 if (field[from_x][from_y] == fill_element)
907 if (safety > max_fieldx * max_fieldy)
908 Error(ERR_EXIT, "Something went wrong in 'FloodFill()'. Please debug.");
910 old_element = field[from_x][from_y];
911 field[from_x][from_y] = fill_element;
913 for (i = 0; i < 4; i++)
915 x = from_x + check[i][0];
916 y = from_y + check[i][1];
918 if (IN_FIELD(x, y, max_fieldx, max_fieldy) && field[x][y] == old_element)
919 FloodFillLevel(x, y, fill_element, field, max_fieldx, max_fieldy);
925 void SetRandomAnimationValue(int x, int y)
927 gfx.anim_random_frame = GfxRandom[x][y];
930 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
932 /* animation synchronized with global frame counter, not move position */
933 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
934 sync_frame = FrameCounter;
936 return getAnimationFrame(graphic_info[graphic].anim_frames,
937 graphic_info[graphic].anim_delay,
938 graphic_info[graphic].anim_mode,
939 graphic_info[graphic].anim_start_frame,
943 void getSizedGraphicSourceExt(int graphic, int frame, int tilesize,
944 Bitmap **bitmap, int *x, int *y,
945 boolean get_backside)
947 struct GraphicInfo *g = &graphic_info[graphic];
948 Bitmap *src_bitmap = g->bitmap;
949 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
950 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
951 int tilesize_capped = MIN(MAX(1, tilesize), TILESIZE);
953 // if no in-game graphics defined, always use standard graphic size
954 if (g->bitmaps[IMG_BITMAP_GAME] == NULL)
957 if (tilesize == gfx.standard_tile_size)
958 src_bitmap = g->bitmaps[IMG_BITMAP_STANDARD];
959 else if (tilesize == game.tile_size)
960 src_bitmap = g->bitmaps[IMG_BITMAP_GAME];
962 src_bitmap = g->bitmaps[IMG_BITMAP_1x1 - log_2(tilesize_capped)];
964 if (g->offset_y == 0) /* frames are ordered horizontally */
966 int max_width = g->anim_frames_per_line * g->width;
967 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
969 src_x = pos % max_width;
970 src_y = src_y % g->height + pos / max_width * g->height;
972 else if (g->offset_x == 0) /* frames are ordered vertically */
974 int max_height = g->anim_frames_per_line * g->height;
975 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
977 src_x = src_x % g->width + pos / max_height * g->width;
978 src_y = pos % max_height;
980 else /* frames are ordered diagonally */
982 src_x = src_x + frame * g->offset_x;
983 src_y = src_y + frame * g->offset_y;
986 *bitmap = src_bitmap;
987 *x = src_x * tilesize / TILESIZE;
988 *y = src_y * tilesize / TILESIZE;
991 void getFixedGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
992 int *x, int *y, boolean get_backside)
994 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y,
998 void getSizedGraphicSource(int graphic, int frame, int tilesize,
999 Bitmap **bitmap, int *x, int *y)
1001 getSizedGraphicSourceExt(graphic, frame, tilesize, bitmap, x, y, FALSE);
1004 void getFixedGraphicSource(int graphic, int frame,
1005 Bitmap **bitmap, int *x, int *y)
1007 getSizedGraphicSourceExt(graphic, frame, TILESIZE, bitmap, x, y, FALSE);
1010 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1012 getSizedGraphicSource(graphic, 0, MINI_TILESIZE, bitmap, x, y);
1015 inline void getGraphicSourceExt(int graphic, int frame, Bitmap **bitmap,
1016 int *x, int *y, boolean get_backside)
1018 struct GraphicInfo *g = &graphic_info[graphic];
1019 int src_x = g->src_x + (get_backside ? g->offset2_x : 0);
1020 int src_y = g->src_y + (get_backside ? g->offset2_y : 0);
1022 if (TILESIZE_VAR != TILESIZE)
1023 return getSizedGraphicSourceExt(graphic, frame, TILESIZE_VAR, bitmap, x, y,
1026 *bitmap = g->bitmap;
1028 if (g->offset_y == 0) /* frames are ordered horizontally */
1030 int max_width = g->anim_frames_per_line * g->width;
1031 int pos = (src_y / g->height) * max_width + src_x + frame * g->offset_x;
1033 *x = pos % max_width;
1034 *y = src_y % g->height + pos / max_width * g->height;
1036 else if (g->offset_x == 0) /* frames are ordered vertically */
1038 int max_height = g->anim_frames_per_line * g->height;
1039 int pos = (src_x / g->width) * max_height + src_y + frame * g->offset_y;
1041 *x = src_x % g->width + pos / max_height * g->width;
1042 *y = pos % max_height;
1044 else /* frames are ordered diagonally */
1046 *x = src_x + frame * g->offset_x;
1047 *y = src_y + frame * g->offset_y;
1051 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
1053 getGraphicSourceExt(graphic, frame, bitmap, x, y, FALSE);
1056 void DrawGraphic(int x, int y, int graphic, int frame)
1059 if (!IN_SCR_FIELD(x, y))
1061 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1062 printf("DrawGraphic(): This should never happen!\n");
1067 DrawGraphicExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR, graphic,
1070 MarkTileDirty(x, y);
1073 void DrawFixedGraphic(int x, int y, int graphic, int frame)
1076 if (!IN_SCR_FIELD(x, y))
1078 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
1079 printf("DrawGraphic(): This should never happen!\n");
1084 DrawFixedGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic,
1086 MarkTileDirty(x, y);
1089 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1095 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1097 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX_VAR, TILEY_VAR, x, y);
1100 void DrawFixedGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
1106 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1107 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
1110 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
1113 if (!IN_SCR_FIELD(x, y))
1115 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1116 printf("DrawGraphicThruMask(): This should never happen!\n");
1121 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
1124 MarkTileDirty(x, y);
1127 void DrawFixedGraphicThruMask(int x, int y, int graphic, int frame)
1130 if (!IN_SCR_FIELD(x, y))
1132 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
1133 printf("DrawGraphicThruMask(): This should never happen!\n");
1138 DrawFixedGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
1140 MarkTileDirty(x, y);
1143 void DrawGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y, int graphic,
1149 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1151 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX_VAR, TILEY_VAR,
1155 void DrawFixedGraphicThruMaskExt(DrawBuffer *d, int dst_x, int dst_y,
1156 int graphic, int frame)
1158 struct GraphicInfo *g = &graphic_info[graphic];
1162 getFixedGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1164 BlitBitmapMasked(src_bitmap, d, src_x, src_y, g->width, g->height,
1168 void DrawSizedGraphic(int x, int y, int graphic, int frame, int tilesize)
1170 DrawSizedGraphicExt(drawto, SX + x * tilesize, SY + y * tilesize, graphic,
1172 MarkTileDirty(x / tilesize, y / tilesize);
1175 void DrawSizedGraphicExt(DrawBuffer *d, int x, int y, int graphic, int frame,
1181 getSizedGraphicSource(graphic, frame, tilesize, &src_bitmap, &src_x, &src_y);
1182 BlitBitmap(src_bitmap, d, src_x, src_y, tilesize, tilesize, x, y);
1185 void DrawMiniGraphic(int x, int y, int graphic)
1187 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1188 MarkTileDirty(x / 2, y / 2);
1191 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1196 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1197 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1200 inline static void DrawGraphicShiftedNormal(int x, int y, int dx, int dy,
1201 int graphic, int frame,
1202 int cut_mode, int mask_mode)
1207 int width = TILEX, height = TILEY;
1210 if (dx || dy) /* shifted graphic */
1212 if (x < BX1) /* object enters playfield from the left */
1219 else if (x > BX2) /* object enters playfield from the right */
1225 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1231 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1233 else if (dx) /* general horizontal movement */
1234 MarkTileDirty(x + SIGN(dx), y);
1236 if (y < BY1) /* object enters playfield from the top */
1238 if (cut_mode==CUT_BELOW) /* object completely above top border */
1246 else if (y > BY2) /* object enters playfield from the bottom */
1252 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1258 else if (dy > 0 && cut_mode == CUT_ABOVE)
1260 if (y == BY2) /* object completely above bottom border */
1266 MarkTileDirty(x, y + 1);
1267 } /* object leaves playfield to the bottom */
1268 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1270 else if (dy) /* general vertical movement */
1271 MarkTileDirty(x, y + SIGN(dy));
1275 if (!IN_SCR_FIELD(x, y))
1277 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1278 printf("DrawGraphicShifted(): This should never happen!\n");
1283 width = width * TILESIZE_VAR / TILESIZE;
1284 height = height * TILESIZE_VAR / TILESIZE;
1285 cx = cx * TILESIZE_VAR / TILESIZE;
1286 cy = cy * TILESIZE_VAR / TILESIZE;
1287 dx = dx * TILESIZE_VAR / TILESIZE;
1288 dy = dy * TILESIZE_VAR / TILESIZE;
1290 if (width > 0 && height > 0)
1292 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1297 dst_x = FX + x * TILEX_VAR + dx;
1298 dst_y = FY + y * TILEY_VAR + dy;
1300 if (mask_mode == USE_MASKING)
1301 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1304 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1307 MarkTileDirty(x, y);
1311 inline static void DrawGraphicShiftedDouble(int x, int y, int dx, int dy,
1312 int graphic, int frame,
1313 int cut_mode, int mask_mode)
1318 int width = TILEX_VAR, height = TILEY_VAR;
1321 int x2 = x + SIGN(dx);
1322 int y2 = y + SIGN(dy);
1324 /* movement with two-tile animations must be sync'ed with movement position,
1325 not with current GfxFrame (which can be higher when using slow movement) */
1326 int anim_pos = (dx ? ABS(dx) : ABS(dy));
1327 int anim_frames = graphic_info[graphic].anim_frames;
1329 /* (we also need anim_delay here for movement animations with less frames) */
1330 int anim_delay = graphic_info[graphic].anim_delay;
1331 int sync_frame = anim_pos * anim_frames * anim_delay / TILESIZE;
1333 boolean draw_start_tile = (cut_mode != CUT_ABOVE); /* only for falling! */
1334 boolean draw_end_tile = (cut_mode != CUT_BELOW); /* only for falling! */
1336 /* re-calculate animation frame for two-tile movement animation */
1337 frame = getGraphicAnimationFrame(graphic, sync_frame);
1339 /* check if movement start graphic inside screen area and should be drawn */
1340 if (draw_start_tile && IN_SCR_FIELD(x1, y1))
1342 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, TRUE);
1344 dst_x = FX + x1 * TILEX_VAR;
1345 dst_y = FY + y1 * TILEY_VAR;
1347 if (mask_mode == USE_MASKING)
1348 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1351 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1354 MarkTileDirty(x1, y1);
1357 /* check if movement end graphic inside screen area and should be drawn */
1358 if (draw_end_tile && IN_SCR_FIELD(x2, y2))
1360 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
1362 dst_x = FX + x2 * TILEX_VAR;
1363 dst_y = FY + y2 * TILEY_VAR;
1365 if (mask_mode == USE_MASKING)
1366 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1369 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1372 MarkTileDirty(x2, y2);
1376 static void DrawGraphicShifted(int x, int y, int dx, int dy,
1377 int graphic, int frame,
1378 int cut_mode, int mask_mode)
1382 DrawGraphic(x, y, graphic, frame);
1387 if (graphic_info[graphic].double_movement) /* EM style movement images */
1388 DrawGraphicShiftedDouble(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1390 DrawGraphicShiftedNormal(x, y, dx, dy, graphic, frame, cut_mode,mask_mode);
1393 void DrawGraphicShiftedThruMask(int x, int y, int dx, int dy, int graphic,
1394 int frame, int cut_mode)
1396 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, USE_MASKING);
1399 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1400 int cut_mode, int mask_mode)
1402 int lx = LEVELX(x), ly = LEVELY(y);
1406 if (IN_LEV_FIELD(lx, ly))
1408 SetRandomAnimationValue(lx, ly);
1410 graphic = el_act_dir2img(element, GfxAction[lx][ly], GfxDir[lx][ly]);
1411 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1413 /* do not use double (EM style) movement graphic when not moving */
1414 if (graphic_info[graphic].double_movement && !dx && !dy)
1416 graphic = el_act_dir2img(element, ACTION_DEFAULT, GfxDir[lx][ly]);
1417 frame = getGraphicAnimationFrame(graphic, GfxFrame[lx][ly]);
1420 else /* border element */
1422 graphic = el2img(element);
1423 frame = getGraphicAnimationFrame(graphic, -1);
1426 if (element == EL_EXPANDABLE_WALL)
1428 boolean left_stopped = FALSE, right_stopped = FALSE;
1430 if (!IN_LEV_FIELD(lx - 1, ly) || IS_WALL(Feld[lx - 1][ly]))
1431 left_stopped = TRUE;
1432 if (!IN_LEV_FIELD(lx + 1, ly) || IS_WALL(Feld[lx + 1][ly]))
1433 right_stopped = TRUE;
1435 if (left_stopped && right_stopped)
1437 else if (left_stopped)
1439 graphic = IMG_EXPANDABLE_WALL_GROWING_RIGHT;
1440 frame = graphic_info[graphic].anim_frames - 1;
1442 else if (right_stopped)
1444 graphic = IMG_EXPANDABLE_WALL_GROWING_LEFT;
1445 frame = graphic_info[graphic].anim_frames - 1;
1450 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1451 else if (mask_mode == USE_MASKING)
1452 DrawGraphicThruMask(x, y, graphic, frame);
1454 DrawGraphic(x, y, graphic, frame);
1457 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1458 int cut_mode, int mask_mode)
1460 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1461 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1462 cut_mode, mask_mode);
1465 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1468 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1471 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1474 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1477 void DrawLevelElementThruMask(int x, int y, int element)
1479 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1482 void DrawLevelFieldThruMask(int x, int y)
1484 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1487 /* !!! implementation of quicksand is totally broken !!! */
1488 #define IS_CRUMBLED_TILE(x, y, e) \
1489 (GFX_CRUMBLED(e) && (!IN_LEV_FIELD(x, y) || \
1490 !IS_MOVING(x, y) || \
1491 (e) == EL_QUICKSAND_EMPTYING || \
1492 (e) == EL_QUICKSAND_FAST_EMPTYING))
1494 static void DrawLevelFieldCrumbledInnerCorners(int x, int y, int dx, int dy,
1499 int width, height, cx, cy;
1500 int sx = SCREENX(x), sy = SCREENY(y);
1501 int crumbled_border_size = graphic_info[graphic].border_size;
1504 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1506 for (i = 1; i < 4; i++)
1508 int dxx = (i & 1 ? dx : 0);
1509 int dyy = (i & 2 ? dy : 0);
1512 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1515 /* check if neighbour field is of same crumble type */
1516 boolean same = (IS_CRUMBLED_TILE(xx, yy, element) &&
1517 graphic_info[graphic].class ==
1518 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class);
1520 /* return if check prevents inner corner */
1521 if (same == (dxx == dx && dyy == dy))
1525 /* if we reach this point, we have an inner corner */
1527 getGraphicSource(graphic, 1, &src_bitmap, &src_x, &src_y);
1529 width = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1530 height = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1531 cx = (dx > 0 ? TILESIZE_VAR - width : 0);
1532 cy = (dy > 0 ? TILESIZE_VAR - height : 0);
1534 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1535 width, height, FX + sx * TILEX_VAR + cx, FY + sy * TILEY_VAR + cy);
1538 static void DrawLevelFieldCrumbledBorders(int x, int y, int graphic, int frame,
1543 int width, height, bx, by, cx, cy;
1544 int sx = SCREENX(x), sy = SCREENY(y);
1545 int crumbled_border_size = graphic_info[graphic].border_size;
1546 int crumbled_border_size_var = crumbled_border_size * TILESIZE_VAR / TILESIZE;
1547 int crumbled_border_pos_var = TILESIZE_VAR - crumbled_border_size_var;
1550 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
1552 /* draw simple, sloppy, non-corner-accurate crumbled border */
1554 width = (dir == 1 || dir == 2 ? crumbled_border_size_var : TILESIZE_VAR);
1555 height = (dir == 0 || dir == 3 ? crumbled_border_size_var : TILESIZE_VAR);
1556 cx = (dir == 2 ? crumbled_border_pos_var : 0);
1557 cy = (dir == 3 ? crumbled_border_pos_var : 0);
1559 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy, width, height,
1560 FX + sx * TILEX_VAR + cx,
1561 FY + sy * TILEY_VAR + cy);
1563 /* (remaining middle border part must be at least as big as corner part) */
1564 if (!(graphic_info[graphic].style & STYLE_ACCURATE_BORDERS) ||
1565 crumbled_border_size >= TILESIZE / 3)
1568 /* correct corners of crumbled border, if needed */
1570 for (i = -1; i <= 1; i += 2)
1572 int xx = x + (dir == 0 || dir == 3 ? i : 0);
1573 int yy = y + (dir == 1 || dir == 2 ? i : 0);
1574 int element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1577 /* check if neighbour field is of same crumble type */
1578 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1579 graphic_info[graphic].class ==
1580 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1582 /* no crumbled corner, but continued crumbled border */
1584 int c1 = (dir == 2 || dir == 3 ? crumbled_border_pos_var : 0);
1585 int c2 = (i == 1 ? crumbled_border_pos_var : 0);
1586 int b1 = (i == 1 ? crumbled_border_size_var :
1587 TILESIZE_VAR - 2 * crumbled_border_size_var);
1589 width = crumbled_border_size_var;
1590 height = crumbled_border_size_var;
1592 if (dir == 1 || dir == 2)
1607 BlitBitmap(src_bitmap, drawto_field, src_x + bx, src_y + by,
1609 FX + sx * TILEX_VAR + cx,
1610 FY + sy * TILEY_VAR + cy);
1615 static void DrawLevelFieldCrumbledExt(int x, int y, int graphic, int frame)
1617 int sx = SCREENX(x), sy = SCREENY(y);
1620 static int xy[4][2] =
1628 if (!IN_LEV_FIELD(x, y))
1631 element = TILE_GFX_ELEMENT(x, y);
1633 /* crumble field itself */
1634 if (IS_CRUMBLED_TILE(x, y, element))
1636 if (!IN_SCR_FIELD(sx, sy))
1639 for (i = 0; i < 4; i++)
1641 int xx = x + xy[i][0];
1642 int yy = y + xy[i][1];
1644 element = (IN_LEV_FIELD(xx, yy) ? TILE_GFX_ELEMENT(xx, yy) :
1647 /* check if neighbour field is of same crumble type */
1648 if (IS_CRUMBLED_TILE(xx, yy, element) &&
1649 graphic_info[graphic].class ==
1650 graphic_info[el_act2crm(element, ACTION_DEFAULT)].class)
1653 DrawLevelFieldCrumbledBorders(x, y, graphic, frame, i);
1656 if ((graphic_info[graphic].style & STYLE_INNER_CORNERS) &&
1657 graphic_info[graphic].anim_frames == 2)
1659 for (i = 0; i < 4; i++)
1661 int dx = (i & 1 ? +1 : -1);
1662 int dy = (i & 2 ? +1 : -1);
1664 DrawLevelFieldCrumbledInnerCorners(x, y, dx, dy, graphic);
1668 MarkTileDirty(sx, sy);
1670 else /* center field not crumbled -- crumble neighbour fields */
1672 for (i = 0; i < 4; i++)
1674 int xx = x + xy[i][0];
1675 int yy = y + xy[i][1];
1676 int sxx = sx + xy[i][0];
1677 int syy = sy + xy[i][1];
1679 if (!IN_LEV_FIELD(xx, yy) ||
1680 !IN_SCR_FIELD(sxx, syy))
1683 if (Feld[xx][yy] == EL_ELEMENT_SNAPPING)
1686 element = TILE_GFX_ELEMENT(xx, yy);
1688 if (!IS_CRUMBLED_TILE(xx, yy, element))
1691 graphic = el_act2crm(element, ACTION_DEFAULT);
1693 DrawLevelFieldCrumbledBorders(xx, yy, graphic, 0, 3 - i);
1695 MarkTileDirty(sxx, syy);
1700 void DrawLevelFieldCrumbled(int x, int y)
1704 if (!IN_LEV_FIELD(x, y))
1707 if (Feld[x][y] == EL_ELEMENT_SNAPPING &&
1708 GfxElement[x][y] != EL_UNDEFINED &&
1709 GFX_CRUMBLED(GfxElement[x][y]))
1711 DrawLevelFieldCrumbledDigging(x, y, GfxDir[x][y], GfxFrame[x][y]);
1716 graphic = el_act2crm(TILE_GFX_ELEMENT(x, y), ACTION_DEFAULT);
1718 DrawLevelFieldCrumbledExt(x, y, graphic, 0);
1721 void DrawLevelFieldCrumbledDigging(int x, int y, int direction,
1724 int graphic1 = el_act_dir2img(GfxElement[x][y], ACTION_DIGGING, direction);
1725 int graphic2 = el_act_dir2crm(GfxElement[x][y], ACTION_DIGGING, direction);
1726 int frame1 = getGraphicAnimationFrame(graphic1, step_frame);
1727 int frame2 = getGraphicAnimationFrame(graphic2, step_frame);
1728 int sx = SCREENX(x), sy = SCREENY(y);
1730 DrawGraphic(sx, sy, graphic1, frame1);
1731 DrawLevelFieldCrumbledExt(x, y, graphic2, frame2);
1734 void DrawLevelFieldCrumbledNeighbours(int x, int y)
1736 int sx = SCREENX(x), sy = SCREENY(y);
1737 static int xy[4][2] =
1746 for (i = 0; i < 4; i++)
1748 int xx = x + xy[i][0];
1749 int yy = y + xy[i][1];
1750 int sxx = sx + xy[i][0];
1751 int syy = sy + xy[i][1];
1753 if (!IN_LEV_FIELD(xx, yy) ||
1754 !IN_SCR_FIELD(sxx, syy) ||
1755 !GFX_CRUMBLED(Feld[xx][yy]) ||
1759 DrawLevelField(xx, yy);
1763 static int getBorderElement(int x, int y)
1767 { EL_STEELWALL_TOPLEFT, EL_INVISIBLE_STEELWALL_TOPLEFT },
1768 { EL_STEELWALL_TOPRIGHT, EL_INVISIBLE_STEELWALL_TOPRIGHT },
1769 { EL_STEELWALL_BOTTOMLEFT, EL_INVISIBLE_STEELWALL_BOTTOMLEFT },
1770 { EL_STEELWALL_BOTTOMRIGHT, EL_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1771 { EL_STEELWALL_VERTICAL, EL_INVISIBLE_STEELWALL_VERTICAL },
1772 { EL_STEELWALL_HORIZONTAL, EL_INVISIBLE_STEELWALL_HORIZONTAL },
1773 { EL_STEELWALL, EL_INVISIBLE_STEELWALL }
1775 int steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1776 int steel_position = (x == -1 && y == -1 ? 0 :
1777 x == lev_fieldx && y == -1 ? 1 :
1778 x == -1 && y == lev_fieldy ? 2 :
1779 x == lev_fieldx && y == lev_fieldy ? 3 :
1780 x == -1 || x == lev_fieldx ? 4 :
1781 y == -1 || y == lev_fieldy ? 5 : 6);
1783 return border[steel_position][steel_type];
1786 void DrawScreenElement(int x, int y, int element)
1788 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1789 DrawLevelFieldCrumbled(LEVELX(x), LEVELY(y));
1792 void DrawLevelElement(int x, int y, int element)
1794 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1795 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1798 void DrawScreenField(int x, int y)
1800 int lx = LEVELX(x), ly = LEVELY(y);
1801 int element, content;
1803 if (!IN_LEV_FIELD(lx, ly))
1805 if (lx < -1 || lx > lev_fieldx || ly < -1 || ly > lev_fieldy)
1808 element = getBorderElement(lx, ly);
1810 DrawScreenElement(x, y, element);
1815 element = Feld[lx][ly];
1816 content = Store[lx][ly];
1818 if (IS_MOVING(lx, ly))
1820 int horiz_move = (MovDir[lx][ly] == MV_LEFT || MovDir[lx][ly] == MV_RIGHT);
1821 boolean cut_mode = NO_CUTTING;
1823 if (element == EL_QUICKSAND_EMPTYING ||
1824 element == EL_QUICKSAND_FAST_EMPTYING ||
1825 element == EL_MAGIC_WALL_EMPTYING ||
1826 element == EL_BD_MAGIC_WALL_EMPTYING ||
1827 element == EL_DC_MAGIC_WALL_EMPTYING ||
1828 element == EL_AMOEBA_DROPPING)
1829 cut_mode = CUT_ABOVE;
1830 else if (element == EL_QUICKSAND_FILLING ||
1831 element == EL_QUICKSAND_FAST_FILLING ||
1832 element == EL_MAGIC_WALL_FILLING ||
1833 element == EL_BD_MAGIC_WALL_FILLING ||
1834 element == EL_DC_MAGIC_WALL_FILLING)
1835 cut_mode = CUT_BELOW;
1837 if (cut_mode == CUT_ABOVE)
1838 DrawScreenElement(x, y, element);
1840 DrawScreenElement(x, y, EL_EMPTY);
1843 DrawScreenElementShifted(x, y, MovPos[lx][ly], 0, element, NO_CUTTING);
1844 else if (cut_mode == NO_CUTTING)
1845 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], element, cut_mode);
1848 DrawScreenElementShifted(x, y, 0, MovPos[lx][ly], content, cut_mode);
1850 if (cut_mode == CUT_BELOW &&
1851 IN_LEV_FIELD(lx, ly + 1) && IN_SCR_FIELD(x, y + 1))
1852 DrawLevelElement(lx, ly + 1, element);
1855 if (content == EL_ACID)
1857 int dir = MovDir[lx][ly];
1858 int newlx = lx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1859 int newly = ly + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1861 DrawLevelElementThruMask(newlx, newly, EL_ACID);
1864 else if (IS_BLOCKED(lx, ly))
1869 boolean cut_mode = NO_CUTTING;
1870 int element_old, content_old;
1872 Blocked2Moving(lx, ly, &oldx, &oldy);
1875 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1876 MovDir[oldx][oldy] == MV_RIGHT);
1878 element_old = Feld[oldx][oldy];
1879 content_old = Store[oldx][oldy];
1881 if (element_old == EL_QUICKSAND_EMPTYING ||
1882 element_old == EL_QUICKSAND_FAST_EMPTYING ||
1883 element_old == EL_MAGIC_WALL_EMPTYING ||
1884 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1885 element_old == EL_DC_MAGIC_WALL_EMPTYING ||
1886 element_old == EL_AMOEBA_DROPPING)
1887 cut_mode = CUT_ABOVE;
1889 DrawScreenElement(x, y, EL_EMPTY);
1892 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1894 else if (cut_mode == NO_CUTTING)
1895 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1898 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1901 else if (IS_DRAWABLE(element))
1902 DrawScreenElement(x, y, element);
1904 DrawScreenElement(x, y, EL_EMPTY);
1907 void DrawLevelField(int x, int y)
1909 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1910 DrawScreenField(SCREENX(x), SCREENY(y));
1911 else if (IS_MOVING(x, y))
1915 Moving2Blocked(x, y, &newx, &newy);
1916 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1917 DrawScreenField(SCREENX(newx), SCREENY(newy));
1919 else if (IS_BLOCKED(x, y))
1923 Blocked2Moving(x, y, &oldx, &oldy);
1924 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1925 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1929 void DrawSizedElement(int x, int y, int element, int tilesize)
1933 graphic = el2edimg(element);
1934 DrawSizedGraphic(x, y, graphic, 0, tilesize);
1937 void DrawMiniElement(int x, int y, int element)
1941 graphic = el2edimg(element);
1942 DrawMiniGraphic(x, y, graphic);
1945 void DrawSizedElementOrWall(int sx, int sy, int scroll_x, int scroll_y,
1948 int x = sx + scroll_x, y = sy + scroll_y;
1950 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1951 DrawSizedElement(sx, sy, EL_EMPTY, tilesize);
1952 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1953 DrawSizedElement(sx, sy, Feld[x][y], tilesize);
1955 DrawSizedGraphic(sx, sy, el2edimg(getBorderElement(x, y)), 0, tilesize);
1958 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1960 int x = sx + scroll_x, y = sy + scroll_y;
1962 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1963 DrawMiniElement(sx, sy, EL_EMPTY);
1964 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1965 DrawMiniElement(sx, sy, Feld[x][y]);
1967 DrawMiniGraphic(sx, sy, el2edimg(getBorderElement(x, y)));
1970 void DrawEnvelopeBackgroundTiles(int graphic, int startx, int starty,
1971 int x, int y, int xsize, int ysize,
1972 int tile_width, int tile_height)
1976 int dst_x = startx + x * tile_width;
1977 int dst_y = starty + y * tile_height;
1978 int width = graphic_info[graphic].width;
1979 int height = graphic_info[graphic].height;
1980 int inner_width_raw = MAX(width - 2 * tile_width, tile_width);
1981 int inner_height_raw = MAX(height - 2 * tile_height, tile_height);
1982 int inner_width = inner_width_raw - (inner_width_raw % tile_width);
1983 int inner_height = inner_height_raw - (inner_height_raw % tile_height);
1984 int inner_sx = (width >= 3 * tile_width ? tile_width : 0);
1985 int inner_sy = (height >= 3 * tile_height ? tile_height : 0);
1986 boolean draw_masked = graphic_info[graphic].draw_masked;
1988 getFixedGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1990 if (src_bitmap == NULL || width < tile_width || height < tile_height)
1992 ClearRectangle(drawto, dst_x, dst_y, tile_width, tile_height);
1996 src_x += (x == 0 ? 0 : x == xsize - 1 ? width - tile_width :
1997 inner_sx + (x - 1) * tile_width % inner_width);
1998 src_y += (y == 0 ? 0 : y == ysize - 1 ? height - tile_height :
1999 inner_sy + (y - 1) * tile_height % inner_height);
2002 BlitBitmapMasked(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2005 BlitBitmap(src_bitmap, drawto, src_x, src_y, tile_width, tile_height,
2009 void DrawEnvelopeBackground(int graphic, int startx, int starty,
2010 int x, int y, int xsize, int ysize, int font_nr)
2012 int font_width = getFontWidth(font_nr);
2013 int font_height = getFontHeight(font_nr);
2015 DrawEnvelopeBackgroundTiles(graphic, startx, starty, x, y, xsize, ysize,
2016 font_width, font_height);
2019 void AnimateEnvelope(int envelope_nr, int anim_mode, int action)
2021 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2022 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2023 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2024 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2025 boolean no_delay = (tape.warp_forward);
2026 unsigned int anim_delay = 0;
2027 int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
2028 int anim_delay_value = (no_delay ? 0 : frame_delay_value) / 2;
2029 int font_nr = FONT_ENVELOPE_1 + envelope_nr;
2030 int font_width = getFontWidth(font_nr);
2031 int font_height = getFontHeight(font_nr);
2032 int max_xsize = level.envelope[envelope_nr].xsize;
2033 int max_ysize = level.envelope[envelope_nr].ysize;
2034 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize : 0);
2035 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize : 0);
2036 int xend = max_xsize;
2037 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize : 0);
2038 int xstep = (xstart < xend ? 1 : 0);
2039 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2041 int end = MAX(xend - xstart, yend - ystart);
2044 for (i = start; i <= end; i++)
2046 int last_frame = end; // last frame of this "for" loop
2047 int x = xstart + i * xstep;
2048 int y = ystart + i * ystep;
2049 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2050 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2051 int sx = SX + (SXSIZE - xsize * font_width) / 2;
2052 int sy = SY + (SYSIZE - ysize * font_height) / 2;
2055 SetDrawtoField(DRAW_FIELDBUFFER);
2057 BlitScreenToBitmap(backbuffer);
2059 SetDrawtoField(DRAW_BACKBUFFER);
2061 for (yy = 0; yy < ysize; yy++)
2062 for (xx = 0; xx < xsize; xx++)
2063 DrawEnvelopeBackground(graphic, sx, sy, xx, yy, xsize, ysize, font_nr);
2065 DrawTextBuffer(sx + font_width, sy + font_height,
2066 level.envelope[envelope_nr].text, font_nr, max_xsize,
2067 xsize - 2, ysize - 2, 0, mask_mode,
2068 level.envelope[envelope_nr].autowrap,
2069 level.envelope[envelope_nr].centered, FALSE);
2071 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2074 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2078 void ShowEnvelope(int envelope_nr)
2080 int element = EL_ENVELOPE_1 + envelope_nr;
2081 int graphic = IMG_BACKGROUND_ENVELOPE_1 + envelope_nr;
2082 int sound_opening = element_info[element].sound[ACTION_OPENING];
2083 int sound_closing = element_info[element].sound[ACTION_CLOSING];
2084 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2085 boolean no_delay = (tape.warp_forward);
2086 int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
2087 int wait_delay_value = (no_delay ? 0 : normal_delay_value);
2088 int anim_mode = graphic_info[graphic].anim_mode;
2089 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2090 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2092 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2094 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2096 if (anim_mode == ANIM_DEFAULT)
2097 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_OPENING);
2099 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_OPENING);
2102 Delay(wait_delay_value);
2104 WaitForEventToContinue();
2106 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2108 if (anim_mode != ANIM_NONE)
2109 AnimateEnvelope(envelope_nr, main_anim_mode, ACTION_CLOSING);
2111 if (anim_mode == ANIM_DEFAULT)
2112 AnimateEnvelope(envelope_nr, ANIM_DEFAULT, ACTION_CLOSING);
2114 game.envelope_active = FALSE;
2116 SetDrawtoField(DRAW_FIELDBUFFER);
2118 redraw_mask |= REDRAW_FIELD;
2122 static void setRequestPosition(int *x, int *y, boolean add_border_size)
2124 int border_size = request.border_size;
2125 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2126 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2127 int sx = sx_center - request.width / 2;
2128 int sy = sy_center - request.height / 2;
2130 if (add_border_size)
2140 void DrawEnvelopeRequest(char *text)
2142 char *text_final = text;
2143 char *text_door_style = NULL;
2144 int graphic = IMG_BACKGROUND_REQUEST;
2145 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
2146 int mask_mode = (src_bitmap != NULL ? BLIT_MASKED : BLIT_ON_BACKGROUND);
2147 int font_nr = FONT_REQUEST;
2148 int font_width = getFontWidth(font_nr);
2149 int font_height = getFontHeight(font_nr);
2150 int border_size = request.border_size;
2151 int line_spacing = request.line_spacing;
2152 int line_height = font_height + line_spacing;
2153 int text_width = request.width - 2 * border_size;
2154 int text_height = request.height - 2 * border_size;
2155 int line_length = text_width / font_width;
2156 int max_lines = text_height / line_height;
2157 int width = request.width;
2158 int height = request.height;
2159 int tile_size = request.step_offset;
2160 int x_steps = width / tile_size;
2161 int y_steps = height / tile_size;
2165 if (request.wrap_single_words)
2167 char *src_text_ptr, *dst_text_ptr;
2169 text_door_style = checked_malloc(2 * strlen(text) + 1);
2171 src_text_ptr = text;
2172 dst_text_ptr = text_door_style;
2174 while (*src_text_ptr)
2176 if (*src_text_ptr == ' ' ||
2177 *src_text_ptr == '?' ||
2178 *src_text_ptr == '!')
2179 *dst_text_ptr++ = '\n';
2181 if (*src_text_ptr != ' ')
2182 *dst_text_ptr++ = *src_text_ptr;
2187 *dst_text_ptr = '\0';
2189 text_final = text_door_style;
2192 setRequestPosition(&sx, &sy, FALSE);
2194 ClearRectangle(backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE);
2196 for (y = 0; y < y_steps; y++)
2197 for (x = 0; x < x_steps; x++)
2198 DrawEnvelopeBackgroundTiles(graphic, sx, sy,
2199 x, y, x_steps, y_steps,
2200 tile_size, tile_size);
2202 DrawTextBuffer(sx + border_size, sy + border_size, text_final, font_nr,
2203 line_length, -1, max_lines, line_spacing, mask_mode,
2204 request.autowrap, request.centered, FALSE);
2206 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
2207 RedrawGadget(tool_gadget[i]);
2209 // store readily prepared envelope request for later use when animating
2210 BlitBitmap(backbuffer, bitmap_db_cross, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2212 if (text_door_style)
2213 free(text_door_style);
2216 void AnimateEnvelopeRequest(int anim_mode, int action)
2218 int graphic = IMG_BACKGROUND_REQUEST;
2219 boolean draw_masked = graphic_info[graphic].draw_masked;
2220 int delay_value_normal = request.step_delay;
2221 int delay_value_fast = delay_value_normal / 2;
2222 boolean ffwd_delay = (tape.playing && tape.fast_forward);
2223 boolean no_delay = (tape.warp_forward);
2224 int delay_value = (ffwd_delay ? delay_value_fast : delay_value_normal);
2225 int anim_delay_value = (no_delay ? 0 : delay_value + 500 * 0) / 2;
2226 unsigned int anim_delay = 0;
2228 int width = request.width;
2229 int height = request.height;
2230 int tile_size = request.step_offset;
2231 int max_xsize = width / tile_size;
2232 int max_ysize = height / tile_size;
2233 int max_xsize_inner = max_xsize - 2;
2234 int max_ysize_inner = max_ysize - 2;
2236 int xstart = (anim_mode & ANIM_VERTICAL ? max_xsize_inner : 0);
2237 int ystart = (anim_mode & ANIM_HORIZONTAL ? max_ysize_inner : 0);
2238 int xend = max_xsize_inner;
2239 int yend = (anim_mode != ANIM_DEFAULT ? max_ysize_inner : 0);
2240 int xstep = (xstart < xend ? 1 : 0);
2241 int ystep = (ystart < yend || xstep == 0 ? 1 : 0);
2243 int end = MAX(xend - xstart, yend - ystart);
2246 if (setup.quick_doors)
2254 if (action == ACTION_OPENING)
2255 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
2256 else if (action == ACTION_CLOSING)
2257 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
2260 for (i = start; i <= end; i++)
2262 int last_frame = end; // last frame of this "for" loop
2263 int x = xstart + i * xstep;
2264 int y = ystart + i * ystep;
2265 int xsize = (action == ACTION_CLOSING ? xend - (x - xstart) : x) + 2;
2266 int ysize = (action == ACTION_CLOSING ? yend - (y - ystart) : y) + 2;
2267 int sx_center = (request.x != -1 ? request.x : SX + SXSIZE / 2);
2268 int sy_center = (request.y != -1 ? request.y : SY + SYSIZE / 2);
2269 int src_x = sx_center - width / 2;
2270 int src_y = sy_center - height / 2;
2271 int dst_x = sx_center - xsize * tile_size / 2;
2272 int dst_y = sy_center - ysize * tile_size / 2;
2273 int xsize_size_left = (xsize - 1) * tile_size;
2274 int ysize_size_top = (ysize - 1) * tile_size;
2275 int max_xsize_pos = (max_xsize - 1) * tile_size;
2276 int max_ysize_pos = (max_ysize - 1) * tile_size;
2279 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2281 for (yy = 0; yy < 2; yy++)
2283 for (xx = 0; xx < 2; xx++)
2285 int src_xx = src_x + xx * max_xsize_pos;
2286 int src_yy = src_y + yy * max_ysize_pos;
2287 int dst_xx = dst_x + xx * xsize_size_left;
2288 int dst_yy = dst_y + yy * ysize_size_top;
2289 int xx_size = (xx ? tile_size : xsize_size_left);
2290 int yy_size = (yy ? tile_size : ysize_size_top);
2293 BlitBitmapMasked(bitmap_db_cross, backbuffer,
2294 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2296 BlitBitmap(bitmap_db_cross, backbuffer,
2297 src_xx, src_yy, xx_size, yy_size, dst_xx, dst_yy);
2301 redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
2306 SkipUntilDelayReached(&anim_delay, anim_delay_value, &i, last_frame);
2311 void ShowEnvelopeRequest(char *text, unsigned int req_state, int action)
2313 int last_game_status = game_status; /* save current game status */
2314 int graphic = IMG_BACKGROUND_REQUEST;
2315 int sound_opening = SND_REQUEST_OPENING;
2316 int sound_closing = SND_REQUEST_CLOSING;
2317 int anim_mode = graphic_info[graphic].anim_mode;
2318 int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
2319 anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);
2321 if (game_status == GAME_MODE_PLAYING)
2322 BlitScreenToBitmap(backbuffer);
2324 SetDrawtoField(DRAW_BACKBUFFER);
2326 // SetDrawBackgroundMask(REDRAW_NONE);
2328 if (action == ACTION_OPENING)
2330 BlitBitmap(backbuffer, bitmap_db_store, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2332 if (req_state & REQ_ASK)
2334 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2335 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2337 else if (req_state & REQ_CONFIRM)
2339 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2341 else if (req_state & REQ_PLAYER)
2343 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2344 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2345 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2346 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2349 DrawEnvelopeRequest(text);
2351 if (game_status != GAME_MODE_MAIN)
2355 /* force DOOR font inside door area */
2356 game_status = GAME_MODE_PSEUDO_DOOR;
2358 game.envelope_active = TRUE; /* needed for RedrawPlayfield() events */
2360 if (action == ACTION_OPENING)
2362 PlayMenuSoundStereo(sound_opening, SOUND_MIDDLE);
2364 if (anim_mode == ANIM_DEFAULT)
2365 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_OPENING);
2367 AnimateEnvelopeRequest(main_anim_mode, ACTION_OPENING);
2371 PlayMenuSoundStereo(sound_closing, SOUND_MIDDLE);
2373 if (anim_mode != ANIM_NONE)
2374 AnimateEnvelopeRequest(main_anim_mode, ACTION_CLOSING);
2376 if (anim_mode == ANIM_DEFAULT)
2377 AnimateEnvelopeRequest(ANIM_DEFAULT, ACTION_CLOSING);
2380 game.envelope_active = FALSE;
2382 game_status = last_game_status; /* restore current game status */
2384 if (action == ACTION_CLOSING)
2386 if (game_status != GAME_MODE_MAIN)
2389 BlitBitmap(bitmap_db_store, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
2392 // SetDrawBackgroundMask(last_draw_background_mask);
2394 redraw_mask |= REDRAW_FIELD;
2396 if (game_status == GAME_MODE_MAIN)
2401 if (action == ACTION_CLOSING &&
2402 game_status == GAME_MODE_PLAYING &&
2403 level.game_engine_type == GAME_ENGINE_TYPE_RND)
2404 SetDrawtoField(DRAW_FIELDBUFFER);
2407 void DrawPreviewElement(int dst_x, int dst_y, int element, int tilesize)
2411 int graphic = el2preimg(element);
2413 getSizedGraphicSource(graphic, 0, tilesize, &src_bitmap, &src_x, &src_y);
2414 BlitBitmap(src_bitmap, drawto, src_x, src_y, tilesize, tilesize, dst_x,dst_y);
2417 void DrawLevel(int draw_background_mask)
2421 SetMainBackgroundImage(IMG_BACKGROUND_PLAYING);
2422 SetDrawBackgroundMask(draw_background_mask);
2426 for (x = BX1; x <= BX2; x++)
2427 for (y = BY1; y <= BY2; y++)
2428 DrawScreenField(x, y);
2430 redraw_mask |= REDRAW_FIELD;
2433 void DrawSizedLevel(int size_x, int size_y, int scroll_x, int scroll_y,
2438 for (x = 0; x < size_x; x++)
2439 for (y = 0; y < size_y; y++)
2440 DrawSizedElementOrWall(x, y, scroll_x, scroll_y, tilesize);
2442 redraw_mask |= REDRAW_FIELD;
2445 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
2449 for (x = 0; x < size_x; x++)
2450 for (y = 0; y < size_y; y++)
2451 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
2453 redraw_mask |= REDRAW_FIELD;
2456 static void DrawPreviewLevelPlayfieldExt(int from_x, int from_y)
2458 boolean show_level_border = (BorderElement != EL_EMPTY);
2459 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2460 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2461 int tile_size = preview.tile_size;
2462 int preview_width = preview.xsize * tile_size;
2463 int preview_height = preview.ysize * tile_size;
2464 int real_preview_xsize = MIN(level_xsize, preview.xsize);
2465 int real_preview_ysize = MIN(level_ysize, preview.ysize);
2466 int real_preview_width = real_preview_xsize * tile_size;
2467 int real_preview_height = real_preview_ysize * tile_size;
2468 int dst_x = SX + ALIGNED_XPOS(preview.x, preview_width, preview.align);
2469 int dst_y = SY + ALIGNED_YPOS(preview.y, preview_height, preview.valign);
2472 if (!IN_GFX_FIELD_FULL(dst_x, dst_y + preview_height - 1))
2475 DrawBackground(dst_x, dst_y, preview_width, preview_height);
2477 dst_x += (preview_width - real_preview_width) / 2;
2478 dst_y += (preview_height - real_preview_height) / 2;
2480 for (x = 0; x < real_preview_xsize; x++)
2482 for (y = 0; y < real_preview_ysize; y++)
2484 int lx = from_x + x + (show_level_border ? -1 : 0);
2485 int ly = from_y + y + (show_level_border ? -1 : 0);
2486 int element = (IN_LEV_FIELD(lx, ly) ? level.field[lx][ly] :
2487 getBorderElement(lx, ly));
2489 DrawPreviewElement(dst_x + x * tile_size, dst_y + y * tile_size,
2490 element, tile_size);
2494 redraw_mask |= REDRAW_MICROLEVEL;
2497 #define MICROLABEL_EMPTY 0
2498 #define MICROLABEL_LEVEL_NAME 1
2499 #define MICROLABEL_LEVEL_AUTHOR_HEAD 2
2500 #define MICROLABEL_LEVEL_AUTHOR 3
2501 #define MICROLABEL_IMPORTED_FROM_HEAD 4
2502 #define MICROLABEL_IMPORTED_FROM 5
2503 #define MICROLABEL_IMPORTED_BY_HEAD 6
2504 #define MICROLABEL_IMPORTED_BY 7
2506 static int getMaxTextLength(struct TextPosInfo *pos, int font_nr)
2508 int max_text_width = SXSIZE;
2509 int font_width = getFontWidth(font_nr);
2511 if (pos->align == ALIGN_CENTER)
2512 max_text_width = (pos->x < SXSIZE / 2 ? pos->x * 2 : (SXSIZE - pos->x) * 2);
2513 else if (pos->align == ALIGN_RIGHT)
2514 max_text_width = pos->x;
2516 max_text_width = SXSIZE - pos->x;
2518 return max_text_width / font_width;
2521 static void DrawPreviewLevelLabelExt(int mode)
2523 struct TextPosInfo *pos = &menu.main.text.level_info_2;
2524 char label_text[MAX_OUTPUT_LINESIZE + 1];
2525 int max_len_label_text;
2526 int font_nr = pos->font;
2529 if (!IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2532 if (mode == MICROLABEL_LEVEL_AUTHOR_HEAD ||
2533 mode == MICROLABEL_IMPORTED_FROM_HEAD ||
2534 mode == MICROLABEL_IMPORTED_BY_HEAD)
2535 font_nr = pos->font_alt;
2537 max_len_label_text = getMaxTextLength(pos, font_nr);
2539 if (pos->size != -1)
2540 max_len_label_text = pos->size;
2542 for (i = 0; i < max_len_label_text; i++)
2543 label_text[i] = ' ';
2544 label_text[max_len_label_text] = '\0';
2546 if (strlen(label_text) > 0)
2547 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2550 (mode == MICROLABEL_LEVEL_NAME ? level.name :
2551 mode == MICROLABEL_LEVEL_AUTHOR_HEAD ? "created by" :
2552 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
2553 mode == MICROLABEL_IMPORTED_FROM_HEAD ? "imported from" :
2554 mode == MICROLABEL_IMPORTED_FROM ? leveldir_current->imported_from :
2555 mode == MICROLABEL_IMPORTED_BY_HEAD ? "imported by" :
2556 mode == MICROLABEL_IMPORTED_BY ? leveldir_current->imported_by :""),
2557 max_len_label_text);
2558 label_text[max_len_label_text] = '\0';
2560 if (strlen(label_text) > 0)
2561 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2563 redraw_mask |= REDRAW_MICROLEVEL;
2566 static void DrawPreviewLevelExt(boolean restart)
2568 static unsigned int scroll_delay = 0;
2569 static unsigned int label_delay = 0;
2570 static int from_x, from_y, scroll_direction;
2571 static int label_state, label_counter;
2572 unsigned int scroll_delay_value = preview.step_delay;
2573 boolean show_level_border = (BorderElement != EL_EMPTY);
2574 int level_xsize = lev_fieldx + (show_level_border ? 2 : 0);
2575 int level_ysize = lev_fieldy + (show_level_border ? 2 : 0);
2576 int last_game_status = game_status; /* save current game status */
2583 if (preview.anim_mode == ANIM_CENTERED)
2585 if (level_xsize > preview.xsize)
2586 from_x = (level_xsize - preview.xsize) / 2;
2587 if (level_ysize > preview.ysize)
2588 from_y = (level_ysize - preview.ysize) / 2;
2591 from_x += preview.xoffset;
2592 from_y += preview.yoffset;
2594 scroll_direction = MV_RIGHT;
2598 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2599 DrawPreviewLevelLabelExt(label_state);
2601 /* initialize delay counters */
2602 DelayReached(&scroll_delay, 0);
2603 DelayReached(&label_delay, 0);
2605 if (leveldir_current->name)
2607 struct TextPosInfo *pos = &menu.main.text.level_info_1;
2608 char label_text[MAX_OUTPUT_LINESIZE + 1];
2609 int font_nr = pos->font;
2610 int max_len_label_text = getMaxTextLength(pos, font_nr);
2612 if (pos->size != -1)
2613 max_len_label_text = pos->size;
2615 strncpy(label_text, leveldir_current->name, max_len_label_text);
2616 label_text[max_len_label_text] = '\0';
2618 if (IN_GFX_FIELD_FULL(pos->x, pos->y + getFontHeight(pos->font)))
2619 DrawTextSAligned(pos->x, pos->y, label_text, font_nr, pos->align);
2622 game_status = last_game_status; /* restore current game status */
2627 /* scroll preview level, if needed */
2628 if (preview.anim_mode != ANIM_NONE &&
2629 (level_xsize > preview.xsize || level_ysize > preview.ysize) &&
2630 DelayReached(&scroll_delay, scroll_delay_value))
2632 switch (scroll_direction)
2637 from_x -= preview.step_offset;
2638 from_x = (from_x < 0 ? 0 : from_x);
2641 scroll_direction = MV_UP;
2645 if (from_x < level_xsize - preview.xsize)
2647 from_x += preview.step_offset;
2648 from_x = (from_x > level_xsize - preview.xsize ?
2649 level_xsize - preview.xsize : from_x);
2652 scroll_direction = MV_DOWN;
2658 from_y -= preview.step_offset;
2659 from_y = (from_y < 0 ? 0 : from_y);
2662 scroll_direction = MV_RIGHT;
2666 if (from_y < level_ysize - preview.ysize)
2668 from_y += preview.step_offset;
2669 from_y = (from_y > level_ysize - preview.ysize ?
2670 level_ysize - preview.ysize : from_y);
2673 scroll_direction = MV_LEFT;
2680 DrawPreviewLevelPlayfieldExt(from_x, from_y);
2683 /* !!! THIS ALL SUCKS -- SHOULD BE CLEANLY REWRITTEN !!! */
2684 /* redraw micro level label, if needed */
2685 if (!strEqual(level.name, NAMELESS_LEVEL_NAME) &&
2686 !strEqual(level.author, ANONYMOUS_NAME) &&
2687 !strEqual(level.author, leveldir_current->name) &&
2688 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
2690 int max_label_counter = 23;
2692 if (leveldir_current->imported_from != NULL &&
2693 strlen(leveldir_current->imported_from) > 0)
2694 max_label_counter += 14;
2695 if (leveldir_current->imported_by != NULL &&
2696 strlen(leveldir_current->imported_by) > 0)
2697 max_label_counter += 14;
2699 label_counter = (label_counter + 1) % max_label_counter;
2700 label_state = (label_counter >= 0 && label_counter <= 7 ?
2701 MICROLABEL_LEVEL_NAME :
2702 label_counter >= 9 && label_counter <= 12 ?
2703 MICROLABEL_LEVEL_AUTHOR_HEAD :
2704 label_counter >= 14 && label_counter <= 21 ?
2705 MICROLABEL_LEVEL_AUTHOR :
2706 label_counter >= 23 && label_counter <= 26 ?
2707 MICROLABEL_IMPORTED_FROM_HEAD :
2708 label_counter >= 28 && label_counter <= 35 ?
2709 MICROLABEL_IMPORTED_FROM :
2710 label_counter >= 37 && label_counter <= 40 ?
2711 MICROLABEL_IMPORTED_BY_HEAD :
2712 label_counter >= 42 && label_counter <= 49 ?
2713 MICROLABEL_IMPORTED_BY : MICROLABEL_EMPTY);
2715 if (leveldir_current->imported_from == NULL &&
2716 (label_state == MICROLABEL_IMPORTED_FROM_HEAD ||
2717 label_state == MICROLABEL_IMPORTED_FROM))
2718 label_state = (label_state == MICROLABEL_IMPORTED_FROM_HEAD ?
2719 MICROLABEL_IMPORTED_BY_HEAD : MICROLABEL_IMPORTED_BY);
2721 DrawPreviewLevelLabelExt(label_state);
2724 game_status = last_game_status; /* restore current game status */
2727 void DrawPreviewLevelInitial()
2729 DrawPreviewLevelExt(TRUE);
2732 void DrawPreviewLevelAnimation()
2734 DrawPreviewLevelExt(FALSE);
2737 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2738 int graphic, int sync_frame, int mask_mode)
2740 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2742 if (mask_mode == USE_MASKING)
2743 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2745 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
2748 inline void DrawFixedGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
2749 int graphic, int sync_frame,
2752 int frame = getGraphicAnimationFrame(graphic, sync_frame);
2754 if (mask_mode == USE_MASKING)
2755 DrawFixedGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
2757 DrawFixedGraphicExt(dst_bitmap, x, y, graphic, frame);
2760 inline void DrawGraphicAnimation(int x, int y, int graphic)
2762 int lx = LEVELX(x), ly = LEVELY(y);
2764 if (!IN_SCR_FIELD(x, y))
2767 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX_VAR, FY + y * TILEY_VAR,
2768 graphic, GfxFrame[lx][ly], NO_MASKING);
2770 MarkTileDirty(x, y);
2773 inline void DrawFixedGraphicAnimation(int x, int y, int graphic)
2775 int lx = LEVELX(x), ly = LEVELY(y);
2777 if (!IN_SCR_FIELD(x, y))
2780 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
2781 graphic, GfxFrame[lx][ly], NO_MASKING);
2782 MarkTileDirty(x, y);
2785 void DrawLevelGraphicAnimation(int x, int y, int graphic)
2787 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2790 void DrawLevelElementAnimation(int x, int y, int element)
2792 int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2794 DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
2797 inline void DrawLevelGraphicAnimationIfNeeded(int x, int y, int graphic)
2799 int sx = SCREENX(x), sy = SCREENY(y);
2801 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2804 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2807 DrawGraphicAnimation(sx, sy, graphic);
2810 if (GFX_CRUMBLED(TILE_GFX_ELEMENT(x, y)))
2811 DrawLevelFieldCrumbled(x, y);
2813 if (GFX_CRUMBLED(Feld[x][y]))
2814 DrawLevelFieldCrumbled(x, y);
2818 void DrawLevelElementAnimationIfNeeded(int x, int y, int element)
2820 int sx = SCREENX(x), sy = SCREENY(y);
2823 if (!IN_LEV_FIELD(x, y) || !IN_SCR_FIELD(sx, sy))
2826 graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
2828 if (!IS_NEW_FRAME(GfxFrame[x][y], graphic))
2831 DrawGraphicAnimation(sx, sy, graphic);
2833 if (GFX_CRUMBLED(element))
2834 DrawLevelFieldCrumbled(x, y);
2837 static int getPlayerGraphic(struct PlayerInfo *player, int move_dir)
2839 if (player->use_murphy)
2841 /* this works only because currently only one player can be "murphy" ... */
2842 static int last_horizontal_dir = MV_LEFT;
2843 int graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, move_dir);
2845 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
2846 last_horizontal_dir = move_dir;
2848 if (graphic == IMG_SP_MURPHY) /* undefined => use special graphic */
2850 int direction = (player->is_snapping ? move_dir : last_horizontal_dir);
2852 graphic = el_act_dir2img(EL_SP_MURPHY, player->GfxAction, direction);
2858 return el_act_dir2img(player->artwork_element, player->GfxAction,move_dir);
2861 static boolean equalGraphics(int graphic1, int graphic2)
2863 struct GraphicInfo *g1 = &graphic_info[graphic1];
2864 struct GraphicInfo *g2 = &graphic_info[graphic2];
2866 return (g1->bitmap == g2->bitmap &&
2867 g1->src_x == g2->src_x &&
2868 g1->src_y == g2->src_y &&
2869 g1->anim_frames == g2->anim_frames &&
2870 g1->anim_delay == g2->anim_delay &&
2871 g1->anim_mode == g2->anim_mode);
2874 void DrawAllPlayers()
2878 for (i = 0; i < MAX_PLAYERS; i++)
2879 if (stored_player[i].active)
2880 DrawPlayer(&stored_player[i]);
2883 void DrawPlayerField(int x, int y)
2885 if (!IS_PLAYER(x, y))
2888 DrawPlayer(PLAYERINFO(x, y));
2891 #define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
2893 void DrawPlayer(struct PlayerInfo *player)
2895 int jx = player->jx;
2896 int jy = player->jy;
2897 int move_dir = player->MovDir;
2898 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
2899 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
2900 int last_jx = (player->is_moving ? jx - dx : jx);
2901 int last_jy = (player->is_moving ? jy - dy : jy);
2902 int next_jx = jx + dx;
2903 int next_jy = jy + dy;
2904 boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
2905 boolean player_is_opaque = FALSE;
2906 int sx = SCREENX(jx), sy = SCREENY(jy);
2907 int sxx = 0, syy = 0;
2908 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
2910 int action = ACTION_DEFAULT;
2911 int last_player_graphic = getPlayerGraphic(player, move_dir);
2912 int last_player_frame = player->Frame;
2915 /* GfxElement[][] is set to the element the player is digging or collecting;
2916 remove also for off-screen player if the player is not moving anymore */
2917 if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
2918 GfxElement[jx][jy] = EL_UNDEFINED;
2920 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
2924 if (!IN_LEV_FIELD(jx, jy))
2926 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
2927 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
2928 printf("DrawPlayerField(): This should never happen!\n");
2933 if (element == EL_EXPLOSION)
2936 action = (player->is_pushing ? ACTION_PUSHING :
2937 player->is_digging ? ACTION_DIGGING :
2938 player->is_collecting ? ACTION_COLLECTING :
2939 player->is_moving ? ACTION_MOVING :
2940 player->is_snapping ? ACTION_SNAPPING :
2941 player->is_dropping ? ACTION_DROPPING :
2942 player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
2944 if (player->is_waiting)
2945 move_dir = player->dir_waiting;
2947 InitPlayerGfxAnimation(player, action, move_dir);
2949 /* ----------------------------------------------------------------------- */
2950 /* draw things in the field the player is leaving, if needed */
2951 /* ----------------------------------------------------------------------- */
2953 if (player->is_moving)
2955 if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
2957 DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
2959 if (last_element == EL_DYNAMITE_ACTIVE ||
2960 last_element == EL_EM_DYNAMITE_ACTIVE ||
2961 last_element == EL_SP_DISK_RED_ACTIVE)
2962 DrawDynamite(last_jx, last_jy);
2964 DrawLevelFieldThruMask(last_jx, last_jy);
2966 else if (last_element == EL_DYNAMITE_ACTIVE ||
2967 last_element == EL_EM_DYNAMITE_ACTIVE ||
2968 last_element == EL_SP_DISK_RED_ACTIVE)
2969 DrawDynamite(last_jx, last_jy);
2971 /* !!! this is not enough to prevent flickering of players which are
2972 moving next to each others without a free tile between them -- this
2973 can only be solved by drawing all players layer by layer (first the
2974 background, then the foreground etc.) !!! => TODO */
2975 else if (!IS_PLAYER(last_jx, last_jy))
2976 DrawLevelField(last_jx, last_jy);
2979 DrawLevelField(last_jx, last_jy);
2982 if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
2983 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
2986 if (!IN_SCR_FIELD(sx, sy))
2989 /* ----------------------------------------------------------------------- */
2990 /* draw things behind the player, if needed */
2991 /* ----------------------------------------------------------------------- */
2994 DrawLevelElement(jx, jy, Back[jx][jy]);
2995 else if (IS_ACTIVE_BOMB(element))
2996 DrawLevelElement(jx, jy, EL_EMPTY);
2999 if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
3001 int old_element = GfxElement[jx][jy];
3002 int old_graphic = el_act_dir2img(old_element, action, move_dir);
3003 int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
3005 if (GFX_CRUMBLED(old_element))
3006 DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
3008 DrawGraphic(sx, sy, old_graphic, frame);
3010 if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
3011 player_is_opaque = TRUE;
3015 GfxElement[jx][jy] = EL_UNDEFINED;
3017 /* make sure that pushed elements are drawn with correct frame rate */
3018 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3020 if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
3021 GfxFrame[jx][jy] = player->StepFrame;
3023 DrawLevelField(jx, jy);
3027 #if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
3028 /* ----------------------------------------------------------------------- */
3029 /* draw player himself */
3030 /* ----------------------------------------------------------------------- */
3032 graphic = getPlayerGraphic(player, move_dir);
3034 /* in the case of changed player action or direction, prevent the current
3035 animation frame from being restarted for identical animations */
3036 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3037 player->Frame = last_player_frame;
3039 frame = getGraphicAnimationFrame(graphic, player->Frame);
3043 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3044 sxx = player->GfxPos;
3046 syy = player->GfxPos;
3049 if (player_is_opaque)
3050 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3052 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3054 if (SHIELD_ON(player))
3056 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3057 IMG_SHIELD_NORMAL_ACTIVE);
3058 int frame = getGraphicAnimationFrame(graphic, -1);
3060 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3064 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3067 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3068 sxx = player->GfxPos;
3070 syy = player->GfxPos;
3074 /* ----------------------------------------------------------------------- */
3075 /* draw things the player is pushing, if needed */
3076 /* ----------------------------------------------------------------------- */
3078 if (player->is_pushing && player->is_moving)
3080 int px = SCREENX(jx), py = SCREENY(jy);
3081 int pxx = (TILEX - ABS(sxx)) * dx;
3082 int pyy = (TILEY - ABS(syy)) * dy;
3083 int gfx_frame = GfxFrame[jx][jy];
3089 if (!IS_MOVING(jx, jy)) /* push movement already finished */
3091 element = Feld[next_jx][next_jy];
3092 gfx_frame = GfxFrame[next_jx][next_jy];
3095 graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
3097 sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
3098 frame = getGraphicAnimationFrame(graphic, sync_frame);
3100 /* draw background element under pushed element (like the Sokoban field) */
3101 if (game.use_masked_pushing && IS_MOVING(jx, jy))
3103 /* this allows transparent pushing animation over non-black background */
3106 DrawLevelElement(jx, jy, Back[jx][jy]);
3108 DrawLevelElement(jx, jy, EL_EMPTY);
3110 if (Back[next_jx][next_jy])
3111 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3113 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
3115 else if (Back[next_jx][next_jy])
3116 DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
3119 /* do not draw (EM style) pushing animation when pushing is finished */
3120 /* (two-tile animations usually do not contain start and end frame) */
3121 if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
3122 DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
3124 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3126 /* masked drawing is needed for EMC style (double) movement graphics */
3127 /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
3128 DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
3132 #if DRAW_PLAYER_OVER_PUSHED_ELEMENT
3133 /* ----------------------------------------------------------------------- */
3134 /* draw player himself */
3135 /* ----------------------------------------------------------------------- */
3137 graphic = getPlayerGraphic(player, move_dir);
3139 /* in the case of changed player action or direction, prevent the current
3140 animation frame from being restarted for identical animations */
3141 if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
3142 player->Frame = last_player_frame;
3144 frame = getGraphicAnimationFrame(graphic, player->Frame);
3148 if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
3149 sxx = player->GfxPos;
3151 syy = player->GfxPos;
3154 if (player_is_opaque)
3155 DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
3157 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3159 if (SHIELD_ON(player))
3161 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
3162 IMG_SHIELD_NORMAL_ACTIVE);
3163 int frame = getGraphicAnimationFrame(graphic, -1);
3165 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
3169 /* ----------------------------------------------------------------------- */
3170 /* draw things in front of player (active dynamite or dynabombs) */
3171 /* ----------------------------------------------------------------------- */
3173 if (IS_ACTIVE_BOMB(element))
3175 graphic = el2img(element);
3176 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
3178 if (game.emulation == EMU_SUPAPLEX)
3179 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
3181 DrawGraphicThruMask(sx, sy, graphic, frame);
3184 if (player_is_moving && last_element == EL_EXPLOSION)
3186 int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
3187 GfxElement[last_jx][last_jy] : EL_EMPTY);
3188 int graphic = el_act2img(element, ACTION_EXPLODING);
3189 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
3190 int phase = ExplodePhase[last_jx][last_jy] - 1;
3191 int frame = getGraphicAnimationFrame(graphic, phase - delay);
3194 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
3197 /* ----------------------------------------------------------------------- */
3198 /* draw elements the player is just walking/passing through/under */
3199 /* ----------------------------------------------------------------------- */
3201 if (player_is_moving)
3203 /* handle the field the player is leaving ... */
3204 if (IS_ACCESSIBLE_INSIDE(last_element))
3205 DrawLevelField(last_jx, last_jy);
3206 else if (IS_ACCESSIBLE_UNDER(last_element))
3207 DrawLevelFieldThruMask(last_jx, last_jy);
3210 /* do not redraw accessible elements if the player is just pushing them */
3211 if (!player_is_moving || !player->is_pushing)
3213 /* ... and the field the player is entering */
3214 if (IS_ACCESSIBLE_INSIDE(element))
3215 DrawLevelField(jx, jy);
3216 else if (IS_ACCESSIBLE_UNDER(element))
3217 DrawLevelFieldThruMask(jx, jy);
3220 MarkTileDirty(sx, sy);
3223 /* ------------------------------------------------------------------------- */
3225 void WaitForEventToContinue()
3227 boolean still_wait = TRUE;
3229 /* simulate releasing mouse button over last gadget, if still pressed */
3231 HandleGadgets(-1, -1, 0);
3233 button_status = MB_RELEASED;
3247 case EVENT_BUTTONPRESS:
3248 case EVENT_KEYPRESS:
3252 case EVENT_KEYRELEASE:
3253 ClearPlayerAction();
3257 HandleOtherEvents(&event);
3261 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3268 /* don't eat all CPU time */
3273 #define MAX_REQUEST_LINES 13
3274 #define MAX_REQUEST_LINE_FONT1_LEN 7
3275 #define MAX_REQUEST_LINE_FONT2_LEN 10
3277 static int RequestHandleEvents(unsigned int req_state)
3279 int last_game_status = game_status; /* save current game status */
3283 button_status = MB_RELEASED;
3285 request_gadget_id = -1;
3294 while (NextValidEvent(&event))
3298 case EVENT_BUTTONPRESS:
3299 case EVENT_BUTTONRELEASE:
3300 case EVENT_MOTIONNOTIFY:
3302 if (event.type == EVENT_MOTIONNOTIFY)
3304 if (!PointerInWindow(window))
3305 continue; /* window and pointer on different screens */
3310 motion_status = TRUE;
3311 mx = ((MotionEvent *) &event)->x;
3312 my = ((MotionEvent *) &event)->y;
3316 motion_status = FALSE;
3317 mx = ((ButtonEvent *) &event)->x;
3318 my = ((ButtonEvent *) &event)->y;
3319 if (event.type == EVENT_BUTTONPRESS)
3320 button_status = ((ButtonEvent *) &event)->button;
3322 button_status = MB_RELEASED;
3325 /* this sets 'request_gadget_id' */
3326 HandleGadgets(mx, my, button_status);
3328 switch (request_gadget_id)
3330 case TOOL_CTRL_ID_YES:
3333 case TOOL_CTRL_ID_NO:
3336 case TOOL_CTRL_ID_CONFIRM:
3337 result = TRUE | FALSE;
3340 case TOOL_CTRL_ID_PLAYER_1:
3343 case TOOL_CTRL_ID_PLAYER_2:
3346 case TOOL_CTRL_ID_PLAYER_3:
3349 case TOOL_CTRL_ID_PLAYER_4:
3360 case EVENT_KEYPRESS:
3361 switch (GetEventKey((KeyEvent *)&event, TRUE))
3364 if (req_state & REQ_CONFIRM)
3369 #if defined(TARGET_SDL2)
3376 #if defined(TARGET_SDL2)
3386 if (req_state & REQ_PLAYER)
3390 case EVENT_KEYRELEASE:
3391 ClearPlayerAction();
3395 HandleOtherEvents(&event);
3400 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
3402 int joy = AnyJoystick();
3404 if (joy & JOY_BUTTON_1)
3406 else if (joy & JOY_BUTTON_2)
3410 if (game_status == GAME_MODE_PLAYING && local_player->LevelSolved_GameEnd)
3412 HandleGameActions();
3418 if (!PendingEvent()) /* delay only if no pending events */
3422 game_status = GAME_MODE_PSEUDO_DOOR;
3426 game_status = last_game_status; /* restore current game status */
3432 static boolean RequestDoor(char *text, unsigned int req_state)
3434 unsigned int old_door_state;
3435 int last_game_status = game_status; /* save current game status */
3436 int max_request_line_len = MAX_REQUEST_LINE_FONT1_LEN;
3437 int font_nr = FONT_TEXT_2;
3442 if (maxWordLengthInString(text) > MAX_REQUEST_LINE_FONT1_LEN)
3444 max_request_line_len = MAX_REQUEST_LINE_FONT2_LEN;
3445 font_nr = FONT_TEXT_1;
3448 if (game_status == GAME_MODE_PLAYING)
3449 BlitScreenToBitmap(backbuffer);
3451 /* disable deactivated drawing when quick-loading level tape recording */
3452 if (tape.playing && tape.deactivate_display)
3453 TapeDeactivateDisplayOff(TRUE);
3455 SetMouseCursor(CURSOR_DEFAULT);
3457 #if defined(NETWORK_AVALIABLE)
3458 /* pause network game while waiting for request to answer */
3459 if (options.network &&
3460 game_status == GAME_MODE_PLAYING &&
3461 req_state & REQUEST_WAIT_FOR_INPUT)
3462 SendToServer_PausePlaying();
3465 old_door_state = GetDoorState();
3467 /* simulate releasing mouse button over last gadget, if still pressed */
3469 HandleGadgets(-1, -1, 0);
3473 /* draw released gadget before proceeding */
3476 if (old_door_state & DOOR_OPEN_1)
3478 CloseDoor(DOOR_CLOSE_1);
3480 /* save old door content */
3481 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3482 0 * DXSIZE, 0, DXSIZE, DYSIZE, 1 * DXSIZE, 0);
3485 SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3486 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3488 /* clear door drawing field */
3489 DrawBackground(DX, DY, DXSIZE, DYSIZE);
3491 /* force DOOR font inside door area */
3492 game_status = GAME_MODE_PSEUDO_DOOR;
3494 /* write text for request */
3495 for (text_ptr = text, ty = 0; ty < MAX_REQUEST_LINES; ty++)
3497 char text_line[max_request_line_len + 1];
3503 for (tl = 0, tx = 0; tx < max_request_line_len; tl++, tx++)
3505 tc = *(text_ptr + tx);
3506 // if (!tc || tc == ' ')
3507 if (!tc || tc == ' ' || tc == '?' || tc == '!')
3511 if ((tc == '?' || tc == '!') && tl == 0)
3521 strncpy(text_line, text_ptr, tl);
3524 DrawText(DX + (DXSIZE - tl * getFontWidth(font_nr)) / 2,
3525 DY + 8 + ty * (getFontHeight(font_nr) + 2),
3526 text_line, font_nr);
3528 text_ptr += tl + (tc == ' ' ? 1 : 0);
3529 // text_ptr += tl + (tc == ' ' || tc == '?' || tc == '!' ? 1 : 0);
3532 game_status = last_game_status; /* restore current game status */
3534 if (req_state & REQ_ASK)
3536 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
3537 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
3539 else if (req_state & REQ_CONFIRM)
3541 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
3543 else if (req_state & REQ_PLAYER)
3545 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
3546 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
3547 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
3548 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
3551 /* copy request gadgets to door backbuffer */
3552 BlitBitmap(drawto, bitmap_db_door_1, DX, DY, DXSIZE, DYSIZE, 0, 0);
3554 OpenDoor(DOOR_OPEN_1);
3556 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3558 if (game_status == GAME_MODE_PLAYING)
3560 SetPanelBackground();
3561 SetDrawBackgroundMask(REDRAW_DOOR_1);
3565 SetDrawBackgroundMask(REDRAW_FIELD);
3571 if (game_status != GAME_MODE_MAIN)
3574 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3576 // ---------- handle request buttons ----------
3577 result = RequestHandleEvents(req_state);
3579 if (game_status != GAME_MODE_MAIN)
3584 if (!(req_state & REQ_STAY_OPEN))
3586 CloseDoor(DOOR_CLOSE_1);
3588 if (((old_door_state & DOOR_OPEN_1) && !(req_state & REQ_STAY_CLOSED)) ||
3589 (req_state & REQ_REOPEN))
3590 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
3595 if (game_status == GAME_MODE_PLAYING)
3597 SetPanelBackground();
3598 SetDrawBackgroundMask(REDRAW_DOOR_1);
3602 SetDrawBackgroundMask(REDRAW_FIELD);
3605 #if defined(NETWORK_AVALIABLE)
3606 /* continue network game after request */
3607 if (options.network &&
3608 game_status == GAME_MODE_PLAYING &&
3609 req_state & REQUEST_WAIT_FOR_INPUT)
3610 SendToServer_ContinuePlaying();
3613 /* restore deactivated drawing when quick-loading level tape recording */
3614 if (tape.playing && tape.deactivate_display)
3615 TapeDeactivateDisplayOn();
3620 static boolean RequestEnvelope(char *text, unsigned int req_state)
3624 if (game_status == GAME_MODE_PLAYING)
3625 BlitScreenToBitmap(backbuffer);
3627 /* disable deactivated drawing when quick-loading level tape recording */
3628 if (tape.playing && tape.deactivate_display)
3629 TapeDeactivateDisplayOff(TRUE);
3631 SetMouseCursor(CURSOR_DEFAULT);
3633 #if defined(NETWORK_AVALIABLE)
3634 /* pause network game while waiting for request to answer */
3635 if (options.network &&
3636 game_status == GAME_MODE_PLAYING &&
3637 req_state & REQUEST_WAIT_FOR_INPUT)
3638 SendToServer_PausePlaying();
3641 /* simulate releasing mouse button over last gadget, if still pressed */
3643 HandleGadgets(-1, -1, 0);
3647 // (replace with setting corresponding request background)
3648 // SetDoorBackgroundImage(IMG_BACKGROUND_DOOR);
3649 // SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3651 /* clear door drawing field */
3652 // DrawBackground(DX, DY, DXSIZE, DYSIZE);
3654 ShowEnvelopeRequest(text, req_state, ACTION_OPENING);
3656 if (!(req_state & REQUEST_WAIT_FOR_INPUT))
3658 if (game_status == GAME_MODE_PLAYING)
3660 SetPanelBackground();
3661 SetDrawBackgroundMask(REDRAW_DOOR_1);
3665 SetDrawBackgroundMask(REDRAW_FIELD);
3671 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
3673 // ---------- handle request buttons ----------
3674 result = RequestHandleEvents(req_state);
3676 if (game_status != GAME_MODE_MAIN)
3681 ShowEnvelopeRequest(text, req_state, ACTION_CLOSING);
3685 if (game_status == GAME_MODE_PLAYING)
3687 SetPanelBackground();
3688 SetDrawBackgroundMask(REDRAW_DOOR_1);
3692 SetDrawBackgroundMask(REDRAW_FIELD);
3695 #if defined(NETWORK_AVALIABLE)
3696 /* continue network game after request */
3697 if (options.network &&
3698 game_status == GAME_MODE_PLAYING &&
3699 req_state & REQUEST_WAIT_FOR_INPUT)
3700 SendToServer_ContinuePlaying();
3703 /* restore deactivated drawing when quick-loading level tape recording */
3704 if (tape.playing && tape.deactivate_display)
3705 TapeDeactivateDisplayOn();
3710 boolean Request(char *text, unsigned int req_state)
3712 if (global.use_envelope_request)
3713 return RequestEnvelope(text, req_state);
3715 return RequestDoor(text, req_state);
3718 static int compareDoorPartOrderInfo(const void *object1, const void *object2)
3720 const struct DoorPartOrderInfo *dpo1 = (struct DoorPartOrderInfo *)object1;
3721 const struct DoorPartOrderInfo *dpo2 = (struct DoorPartOrderInfo *)object2;
3724 if (dpo1->sort_priority != dpo2->sort_priority)
3725 compare_result = dpo1->sort_priority - dpo2->sort_priority;
3727 compare_result = dpo1->nr - dpo2->nr;
3729 return compare_result;
3732 void InitGraphicCompatibilityInfo_Doors()
3738 struct DoorInfo *door;
3742 { DOOR_1, IMG_DOOR_1_GFX_PART_1, IMG_DOOR_1_GFX_PART_8, &door_1 },
3743 { DOOR_2, IMG_DOOR_2_GFX_PART_1, IMG_DOOR_2_GFX_PART_8, &door_2 },
3745 { -1, -1, -1, NULL }
3747 struct Rect door_rect_list[] =
3749 { DX, DY, DXSIZE, DYSIZE },
3750 { VX, VY, VXSIZE, VYSIZE }
3754 for (i = 0; doors[i].door_token != -1; i++)
3756 int door_token = doors[i].door_token;
3757 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
3758 int part_1 = doors[i].part_1;
3759 int part_8 = doors[i].part_8;
3760 int part_2 = part_1 + 1;
3761 int part_3 = part_1 + 2;
3762 struct DoorInfo *door = doors[i].door;
3763 struct Rect *door_rect = &door_rect_list[door_index];
3764 boolean door_gfx_redefined = FALSE;
3766 /* check if any door part graphic definitions have been redefined */
3768 for (j = 0; door_part_controls[j].door_token != -1; j++)
3770 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3771 struct FileInfo *fi = getImageListEntryFromImageID(dpc->graphic);
3773 if (dpc->door_token == door_token && fi->redefined)
3774 door_gfx_redefined = TRUE;
3777 /* check for old-style door graphic/animation modifications */
3779 if (!door_gfx_redefined)
3781 if (door->anim_mode & ANIM_STATIC_PANEL)
3783 door->panel.step_xoffset = 0;
3784 door->panel.step_yoffset = 0;
3787 if (door->anim_mode & (ANIM_HORIZONTAL | ANIM_VERTICAL))
3789 struct GraphicInfo *g_part_1 = &graphic_info[part_1];
3790 struct GraphicInfo *g_part_2 = &graphic_info[part_2];
3791 int num_door_steps, num_panel_steps;
3793 /* remove door part graphics other than the two default wings */
3795 for (j = 0; door_part_controls[j].door_token != -1; j++)
3797 struct DoorPartControlInfo *dpc = &door_part_controls[j];
3798 struct GraphicInfo *g = &graphic_info[dpc->graphic];
3800 if (dpc->graphic >= part_3 &&
3801 dpc->graphic <= part_8)
3805 /* set graphics and screen positions of the default wings */
3807 g_part_1->width = door_rect->width;
3808 g_part_1->height = door_rect->height;
3809 g_part_2->width = door_rect->width;
3810 g_part_2->height = door_rect->height;
3811 g_part_2->src_x = door_rect->width;
3812 g_part_2->src_y = g_part_1->src_y;
3814 door->part_2.x = door->part_1.x;
3815 door->part_2.y = door->part_1.y;
3817 if (door->width != -1)
3819 g_part_1->width = door->width;
3820 g_part_2->width = door->width;
3822 // special treatment for graphics and screen position of right wing
3823 g_part_2->src_x += door_rect->width - door->width;
3824 door->part_2.x += door_rect->width - door->width;
3827 if (door->height != -1)
3829 g_part_1->height = door->height;
3830 g_part_2->height = door->height;
3832 // special treatment for graphics and screen position of bottom wing
3833 g_part_2->src_y += door_rect->height - door->height;
3834 door->part_2.y += door_rect->height - door->height;
3837 /* set animation delays for the default wings and panels */
3839 door->part_1.step_delay = door->step_delay;
3840 door->part_2.step_delay = door->step_delay;
3841 door->panel.step_delay = door->step_delay;
3843 /* set animation draw order for the default wings */
3845 door->part_1.sort_priority = 2; /* draw left wing over ... */
3846 door->part_2.sort_priority = 1; /* ... right wing */
3848 /* set animation draw offset for the default wings */
3850 if (door->anim_mode & ANIM_HORIZONTAL)
3852 door->part_1.step_xoffset = door->step_offset;
3853 door->part_1.step_yoffset = 0;
3854 door->part_2.step_xoffset = door->step_offset * -1;
3855 door->part_2.step_yoffset = 0;
3857 num_door_steps = g_part_1->width / door->step_offset;
3859 else // ANIM_VERTICAL
3861 door->part_1.step_xoffset = 0;
3862 door->part_1.step_yoffset = door->step_offset;
3863 door->part_2.step_xoffset = 0;
3864 door->part_2.step_yoffset = door->step_offset * -1;
3866 num_door_steps = g_part_1->height / door->step_offset;
3869 /* set animation draw offset for the default panels */
3871 if (door->step_offset > 1)
3873 num_panel_steps = 2 * door_rect->height / door->step_offset;
3874 door->panel.start_step = num_panel_steps - num_door_steps;
3875 door->panel.start_step_closing = door->panel.start_step;
3879 num_panel_steps = door_rect->height / door->step_offset;
3880 door->panel.start_step = num_panel_steps - num_door_steps / 2;
3881 door->panel.start_step_closing = door->panel.start_step;
3882 door->panel.step_delay *= 2;
3893 for (i = 0; door_part_controls[i].door_token != -1; i++)
3895 struct DoorPartControlInfo *dpc = &door_part_controls[i];
3896 struct DoorPartOrderInfo *dpo = &door_part_order[i];
3898 /* initialize "start_step_opening" and "start_step_closing", if needed */
3899 if (dpc->pos->start_step_opening == 0 &&
3900 dpc->pos->start_step_closing == 0)
3902 // dpc->pos->start_step_opening = dpc->pos->start_step;
3903 dpc->pos->start_step_closing = dpc->pos->start_step;
3906 /* fill structure for door part draw order (sorted below) */
3908 dpo->sort_priority = dpc->pos->sort_priority;
3911 /* sort door part controls according to sort_priority and graphic number */
3912 qsort(door_part_order, MAX_DOOR_PARTS,
3913 sizeof(struct DoorPartOrderInfo), compareDoorPartOrderInfo);
3916 unsigned int OpenDoor(unsigned int door_state)
3918 if (door_state & DOOR_COPY_BACK)
3920 if (door_state & DOOR_OPEN_1)
3921 BlitBitmap(bitmap_db_door_1, bitmap_db_door_1,
3922 1 * DXSIZE, 0, DXSIZE, DYSIZE, 0 * DXSIZE, 0);
3924 if (door_state & DOOR_OPEN_2)
3925 BlitBitmap(bitmap_db_door_2, bitmap_db_door_2,
3926 1 * VXSIZE, 0, VXSIZE, VYSIZE, 0 * VXSIZE, 0);
3928 door_state &= ~DOOR_COPY_BACK;
3931 return MoveDoor(door_state);
3934 unsigned int CloseDoor(unsigned int door_state)
3936 unsigned int old_door_state = GetDoorState();
3938 if (!(door_state & DOOR_NO_COPY_BACK))
3940 if (old_door_state & DOOR_OPEN_1)
3941 BlitBitmap(backbuffer, bitmap_db_door_1,
3942 DX, DY, DXSIZE, DYSIZE, 0, 0);
3944 if (old_door_state & DOOR_OPEN_2)
3945 BlitBitmap(backbuffer, bitmap_db_door_2,
3946 VX, VY, VXSIZE, VYSIZE, 0, 0);
3948 door_state &= ~DOOR_NO_COPY_BACK;
3951 return MoveDoor(door_state);
3954 unsigned int GetDoorState()
3956 return MoveDoor(DOOR_GET_STATE);
3959 unsigned int SetDoorState(unsigned int door_state)
3961 return MoveDoor(door_state | DOOR_SET_STATE);
3964 int euclid(int a, int b)
3966 return (b ? euclid(b, a % b) : a);
3969 unsigned int MoveDoor(unsigned int door_state)
3971 struct Rect door_rect_list[] =
3973 { DX, DY, DXSIZE, DYSIZE },
3974 { VX, VY, VXSIZE, VYSIZE }
3976 static int door1 = DOOR_OPEN_1;
3977 static int door2 = DOOR_CLOSE_2;
3978 unsigned int door_delay = 0;
3979 unsigned int door_delay_value;
3982 if (door_state == DOOR_GET_STATE)
3983 return (door1 | door2);
3985 if (door_state & DOOR_SET_STATE)
3987 if (door_state & DOOR_ACTION_1)
3988 door1 = door_state & DOOR_ACTION_1;
3989 if (door_state & DOOR_ACTION_2)
3990 door2 = door_state & DOOR_ACTION_2;
3992 return (door1 | door2);
3995 if (!(door_state & DOOR_FORCE_REDRAW))
3997 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
3998 door_state &= ~DOOR_OPEN_1;
3999 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
4000 door_state &= ~DOOR_CLOSE_1;
4001 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
4002 door_state &= ~DOOR_OPEN_2;
4003 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
4004 door_state &= ~DOOR_CLOSE_2;
4007 if (global.autoplay_leveldir)
4009 door_state |= DOOR_NO_DELAY;
4010 door_state &= ~DOOR_CLOSE_ALL;
4013 if (game_status == GAME_MODE_EDITOR)
4014 door_state |= DOOR_NO_DELAY;
4016 if (door_state & DOOR_ACTION)
4018 boolean door_panel_drawn[NUM_DOORS];
4019 boolean panel_has_doors[NUM_DOORS];
4020 boolean door_part_skip[MAX_DOOR_PARTS];
4021 boolean door_part_done[MAX_DOOR_PARTS];
4022 boolean door_part_done_all;
4023 int num_steps[MAX_DOOR_PARTS];
4024 int max_move_delay = 0; // delay for complete animations of all doors
4025 int max_step_delay = 0; // delay (ms) between two animation frames
4026 int num_move_steps = 0; // number of animation steps for all doors
4027 int max_move_delay_doors_only = 0; // delay for doors only (no panel)
4028 int num_move_steps_doors_only = 0; // steps for doors only (no panel)
4029 int current_move_delay = 0;
4033 for (i = 0; i < NUM_DOORS; i++)
4034 panel_has_doors[i] = FALSE;
4036 for (i = 0; i < MAX_DOOR_PARTS; i++)
4038 struct DoorPartControlInfo *dpc = &door_part_controls[i];
4039 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4040 int door_token = dpc->door_token;
4042 door_part_done[i] = FALSE;
4043 door_part_skip[i] = (!(door_state & door_token) ||
4047 for (i = 0; i < MAX_DOOR_PARTS; i++)
4049 int nr = door_part_order[i].nr;
4050 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4051 struct DoorPartPosInfo *pos = dpc->pos;
4052 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4053 int door_token = dpc->door_token;
4054 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4055 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4056 int step_xoffset = ABS(pos->step_xoffset);
4057 int step_yoffset = ABS(pos->step_yoffset);
4058 int step_delay = pos->step_delay;
4059 int current_door_state = door_state & door_token;
4060 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4061 boolean door_closing = ((current_door_state & DOOR_CLOSE) != 0);
4062 boolean part_opening = (is_panel ? door_closing : door_opening);
4063 int start_step = (part_opening ? pos->start_step_opening :
4064 pos->start_step_closing);
4065 float move_xsize = (step_xoffset ? g->width : 0);
4066 float move_ysize = (step_yoffset ? g->height : 0);
4067 int move_xsteps = (step_xoffset ? ceil(move_xsize / step_xoffset) : 0);
4068 int move_ysteps = (step_yoffset ? ceil(move_ysize / step_yoffset) : 0);
4069 int move_steps = (move_xsteps && move_ysteps ?
4070 MIN(move_xsteps, move_ysteps) :
4071 move_xsteps ? move_xsteps : move_ysteps) - start_step;
4072 int move_delay = move_steps * step_delay;
4074 if (door_part_skip[nr])
4077 max_move_delay = MAX(max_move_delay, move_delay);
4078 max_step_delay = (max_step_delay == 0 ? step_delay :
4079 euclid(max_step_delay, step_delay));
4080 num_steps[nr] = move_steps;
4084 max_move_delay_doors_only = MAX(max_move_delay_doors_only, move_delay);
4086 panel_has_doors[door_index] = TRUE;
4090 max_step_delay = MAX(1, max_step_delay); // prevent division by zero
4092 num_move_steps = max_move_delay / max_step_delay;
4093 num_move_steps_doors_only = max_move_delay_doors_only / max_step_delay;
4095 door_delay_value = max_step_delay;
4097 if ((door_state & DOOR_NO_DELAY) || setup.quick_doors)
4099 start = num_move_steps - 1;
4103 /* opening door sound has priority over simultaneously closing door */
4104 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
4105 PlayMenuSoundStereo(SND_DOOR_OPENING, SOUND_MIDDLE);
4106 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
4107 PlayMenuSoundStereo(SND_DOOR_CLOSING, SOUND_MIDDLE);
4110 for (k = start; k < num_move_steps; k++)
4112 int last_frame = num_move_steps - 1; // last frame of this "for" loop
4114 door_part_done_all = TRUE;
4116 for (i = 0; i < NUM_DOORS; i++)
4117 door_panel_drawn[i] = FALSE;
4119 for (i = 0; i < MAX_DOOR_PARTS; i++)
4121 int nr = door_part_order[i].nr;
4122 struct DoorPartControlInfo *dpc = &door_part_controls[nr];
4123 struct DoorPartPosInfo *pos = dpc->pos;
4124 struct GraphicInfo *g = &graphic_info[dpc->graphic];
4125 int door_token = dpc->door_token;
4126 int door_index = DOOR_INDEX_FROM_TOKEN(door_token);
4127 boolean is_panel = DOOR_PART_IS_PANEL(nr);
4128 boolean is_panel_and_door_has_closed = FALSE;
4129 struct Rect *door_rect = &door_rect_list[door_index];
4130 Bitmap *bitmap_db_door = (door_token == DOOR_1 ? bitmap_db_door_1 :
4132 Bitmap *bitmap = (is_panel ? bitmap_db_door : g->bitmap);
4133 int current_door_state = door_state & door_token;
4134 boolean door_opening = ((current_door_state & DOOR_OPEN) != 0);
4135 boolean door_closing = !door_opening;
4136 boolean part_opening = (is_panel ? door_closing : door_opening);
4137 boolean part_closing = !part_opening;
4138 int start_step = (part_opening ? pos->start_step_opening :
4139 pos->start_step_closing);
4140 int step_delay = pos->step_delay;
4141 int step_factor = step_delay / max_step_delay;
4142 int k1 = (step_factor ? k / step_factor + 1 : k);
4143 int k2 = (part_opening ? k1 + start_step : num_steps[nr] - k1);
4144 int kk = MAX(0, k2);
4147 int src_x, src_y, src_xx, src_yy;
4148 int dst_x, dst_y, dst_xx, dst_yy;
4151 if (door_part_skip[nr])
4154 if (!(door_state & door_token))
4162 int k2_door = (door_opening ? k : num_move_steps_doors_only - k - 1);
4163 int kk_door = MAX(0, k2_door);
4164 int sync_frame = kk_door * door_delay_value;
4165 int frame = getGraphicAnimationFrame(dpc->graphic, sync_frame);
4167 getGraphicSource(dpc->graphic, frame, &bitmap, &g_src_x, &g_src_y);
4172 if (!door_panel_drawn[door_index])
4174 ClearRectangle(drawto, door_rect->x, door_rect->y,
4175 door_rect->width, door_rect->height);
4177 door_panel_drawn[door_index] = TRUE;
4180 // draw opening or closing door parts
4182 if (pos->step_xoffset < 0) // door part on right side
4185 dst_xx = pos->x + ABS(kk * pos->step_xoffset);
4188 if (dst_xx + width > door_rect->width)
4189 width = door_rect->width - dst_xx;
4191 else // door part on left side
4194 dst_xx = pos->x - kk * pos->step_xoffset;
4198 src_xx = ABS(dst_xx);
4202 width = g->width - src_xx;
4204 // printf("::: k == %d [%d] \n", k, start_step);
4207 if (pos->step_yoffset < 0) // door part on bottom side
4210 dst_yy = pos->y + ABS(kk * pos->step_yoffset);
4213 if (dst_yy + height > door_rect->height)
4214 height = door_rect->height - dst_yy;
4216 else // door part on top side
4219 dst_yy = pos->y - kk * pos->step_yoffset;
4223 src_yy = ABS(dst_yy);
4227 height = g->height - src_yy;
4230 src_x = g_src_x + src_xx;
4231 src_y = g_src_y + src_yy;
4233 dst_x = door_rect->x + dst_xx;
4234 dst_y = door_rect->y + dst_yy;
4236 is_panel_and_door_has_closed =
4239 panel_has_doors[door_index] &&
4240 k >= num_move_steps_doors_only - 1);
4242 if (width >= 0 && width <= g->width &&
4243 height >= 0 && height <= g->height &&
4244 !is_panel_and_door_has_closed)
4246 if (is_panel || !pos->draw_masked)
4247 BlitBitmap(bitmap, drawto, src_x, src_y, width, height,
4250 BlitBitmapMasked(bitmap, drawto, src_x, src_y, width, height,
4254 redraw_mask |= REDRAW_DOOR_FROM_TOKEN(door_token);
4256 if ((part_opening && (width < 0 || height < 0)) ||
4257 (part_closing && (width >= g->width && height >= g->height)))
4258 door_part_done[nr] = TRUE;
4260 // continue door part animations, but not panel after door has closed
4261 if (!door_part_done[nr] && !is_panel_and_door_has_closed)
4262 door_part_done_all = FALSE;
4265 if (!(door_state & DOOR_NO_DELAY))
4269 if (game_status == GAME_MODE_MAIN)
4272 SkipUntilDelayReached(&door_delay, door_delay_value, &k, last_frame);
4274 current_move_delay += max_step_delay;
4277 if (door_part_done_all)
4282 if (door_state & DOOR_ACTION_1)
4283 door1 = door_state & DOOR_ACTION_1;
4284 if (door_state & DOOR_ACTION_2)
4285 door2 = door_state & DOOR_ACTION_2;
4287 return (door1 | door2);
4290 void DrawSpecialEditorDoor()
4292 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4293 int top_border_width = gfx1->width;
4294 int top_border_height = gfx1->height;
4295 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4296 int ex = EX - outer_border;
4297 int ey = EY - outer_border;
4298 int vy = VY - outer_border;
4299 int exsize = EXSIZE + 2 * outer_border;
4301 /* draw bigger level editor toolbox window */
4302 BlitBitmap(gfx1->bitmap, drawto, gfx1->src_x, gfx1->src_y,
4303 top_border_width, top_border_height, ex, ey - top_border_height);
4304 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto, ex, vy,
4305 exsize, EYSIZE - VYSIZE + outer_border, ex, ey);
4307 redraw_mask |= REDRAW_ALL;
4310 void UndrawSpecialEditorDoor()
4312 struct GraphicInfo *gfx1 = &graphic_info[IMG_DOOR_2_TOP_BORDER_CORRECTION];
4313 int top_border_width = gfx1->width;
4314 int top_border_height = gfx1->height;
4315 int outer_border = viewport.door_2[GAME_MODE_EDITOR].border_size;
4316 int ex = EX - outer_border;
4317 int ey = EY - outer_border;
4318 int ey_top = ey - top_border_height;
4319 int exsize = EXSIZE + 2 * outer_border;
4320 int eysize = EYSIZE + 2 * outer_border;
4322 /* draw normal tape recorder window */
4323 if (graphic_info[IMG_GLOBAL_BORDER].bitmap)
4325 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4326 ex, ey_top, top_border_width, top_border_height,
4328 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
4329 ex, ey, exsize, eysize, ex, ey);
4333 // if screen background is set to "[NONE]", clear editor toolbox window
4334 ClearRectangle(drawto, ex, ey_top, top_border_width, top_border_height);
4335 ClearRectangle(drawto, ex, ey, exsize, eysize);
4338 redraw_mask |= REDRAW_ALL;
4342 /* ---------- new tool button stuff ---------------------------------------- */
4347 struct TextPosInfo *pos;
4350 } toolbutton_info[NUM_TOOL_BUTTONS] =
4353 IMG_REQUEST_BUTTON_GFX_YES, &request.button.yes,
4354 TOOL_CTRL_ID_YES, "yes"
4357 IMG_REQUEST_BUTTON_GFX_NO, &request.button.no,
4358 TOOL_CTRL_ID_NO, "no"
4361 IMG_REQUEST_BUTTON_GFX_CONFIRM, &request.button.confirm,
4362 TOOL_CTRL_ID_CONFIRM, "confirm"
4365 IMG_REQUEST_BUTTON_GFX_PLAYER_1, &request.button.player_1,
4366 TOOL_CTRL_ID_PLAYER_1, "player 1"
4369 IMG_REQUEST_BUTTON_GFX_PLAYER_2, &request.button.player_2,
4370 TOOL_CTRL_ID_PLAYER_2, "player 2"
4373 IMG_REQUEST_BUTTON_GFX_PLAYER_3, &request.button.player_3,
4374 TOOL_CTRL_ID_PLAYER_3, "player 3"
4377 IMG_REQUEST_BUTTON_GFX_PLAYER_4, &request.button.player_4,
4378 TOOL_CTRL_ID_PLAYER_4, "player 4"
4382 void CreateToolButtons()
4386 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4388 struct GraphicInfo *gfx = &graphic_info[toolbutton_info[i].graphic];
4389 struct TextPosInfo *pos = toolbutton_info[i].pos;
4390 struct GadgetInfo *gi;
4391 Bitmap *deco_bitmap = None;
4392 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
4393 unsigned int event_mask = GD_EVENT_RELEASED;
4396 int gd_x = gfx->src_x;
4397 int gd_y = gfx->src_y;
4398 int gd_xp = gfx->src_x + gfx->pressed_xoffset;
4399 int gd_yp = gfx->src_y + gfx->pressed_yoffset;
4402 if (global.use_envelope_request)
4403 setRequestPosition(&dx, &dy, TRUE);
4405 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
4407 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
4409 getSizedGraphicSource(PLAYER_NR_GFX(IMG_PLAYER_1, player_nr), 0,
4410 pos->size, &deco_bitmap, &deco_x, &deco_y);
4411 deco_xpos = (gfx->width - pos->size) / 2;
4412 deco_ypos = (gfx->height - pos->size) / 2;
4415 gi = CreateGadget(GDI_CUSTOM_ID, id,
4416 GDI_INFO_TEXT, toolbutton_info[i].infotext,
4417 GDI_X, dx + GDI_ACTIVE_POS(pos->x),
4418 GDI_Y, dy + GDI_ACTIVE_POS(pos->y),
4419 GDI_WIDTH, gfx->width,
4420 GDI_HEIGHT, gfx->height,
4421 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
4422 GDI_STATE, GD_BUTTON_UNPRESSED,
4423 GDI_DESIGN_UNPRESSED, gfx->bitmap, gd_x, gd_y,
4424 GDI_DESIGN_PRESSED, gfx->bitmap, gd_xp, gd_yp,
4425 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
4426 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
4427 GDI_DECORATION_SIZE, pos->size, pos->size,
4428 GDI_DECORATION_SHIFTING, 1, 1,
4429 GDI_DIRECT_DRAW, FALSE,
4430 GDI_EVENT_MASK, event_mask,
4431 GDI_CALLBACK_ACTION, HandleToolButtons,
4435 Error(ERR_EXIT, "cannot create gadget");
4437 tool_gadget[id] = gi;
4441 void FreeToolButtons()
4445 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4446 FreeGadget(tool_gadget[i]);
4449 static void UnmapToolButtons()
4453 for (i = 0; i < NUM_TOOL_BUTTONS; i++)
4454 UnmapGadget(tool_gadget[i]);
4457 static void HandleToolButtons(struct GadgetInfo *gi)
4459 request_gadget_id = gi->custom_id;
4462 static struct Mapping_EM_to_RND_object
4465 boolean is_rnd_to_em_mapping; /* unique mapping EM <-> RND */
4466 boolean is_backside; /* backside of moving element */
4472 em_object_mapping_list[] =
4475 Xblank, TRUE, FALSE,
4479 Yacid_splash_eB, FALSE, FALSE,
4480 EL_ACID_SPLASH_RIGHT, -1, -1
4483 Yacid_splash_wB, FALSE, FALSE,
4484 EL_ACID_SPLASH_LEFT, -1, -1
4487 #ifdef EM_ENGINE_BAD_ROLL
4489 Xstone_force_e, FALSE, FALSE,
4490 EL_ROCK, -1, MV_BIT_RIGHT
4493 Xstone_force_w, FALSE, FALSE,
4494 EL_ROCK, -1, MV_BIT_LEFT
4497 Xnut_force_e, FALSE, FALSE,
4498 EL_NUT, -1, MV_BIT_RIGHT
4501 Xnut_force_w, FALSE, FALSE,
4502 EL_NUT, -1, MV_BIT_LEFT
4505 Xspring_force_e, FALSE, FALSE,
4506 EL_SPRING, -1, MV_BIT_RIGHT
4509 Xspring_force_w, FALSE, FALSE,
4510 EL_SPRING, -1, MV_BIT_LEFT
4513 Xemerald_force_e, FALSE, FALSE,
4514 EL_EMERALD, -1, MV_BIT_RIGHT
4517 Xemerald_force_w, FALSE, FALSE,
4518 EL_EMERALD, -1, MV_BIT_LEFT
4521 Xdiamond_force_e, FALSE, FALSE,
4522 EL_DIAMOND, -1, MV_BIT_RIGHT
4525 Xdiamond_force_w, FALSE, FALSE,
4526 EL_DIAMOND, -1, MV_BIT_LEFT
4529 Xbomb_force_e, FALSE, FALSE,
4530 EL_BOMB, -1, MV_BIT_RIGHT
4533 Xbomb_force_w, FALSE, FALSE,
4534 EL_BOMB, -1, MV_BIT_LEFT
4536 #endif /* EM_ENGINE_BAD_ROLL */
4539 Xstone, TRUE, FALSE,
4543 Xstone_pause, FALSE, FALSE,
4547 Xstone_fall, FALSE, FALSE,
4551 Ystone_s, FALSE, FALSE,
4552 EL_ROCK, ACTION_FALLING, -1
4555 Ystone_sB, FALSE, TRUE,
4556 EL_ROCK, ACTION_FALLING, -1
4559 Ystone_e, FALSE, FALSE,
4560 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4563 Ystone_eB, FALSE, TRUE,
4564 EL_ROCK, ACTION_MOVING, MV_BIT_RIGHT
4567 Ystone_w, FALSE, FALSE,
4568 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4571 Ystone_wB, FALSE, TRUE,
4572 EL_ROCK, ACTION_MOVING, MV_BIT_LEFT
4579 Xnut_pause, FALSE, FALSE,
4583 Xnut_fall, FALSE, FALSE,
4587 Ynut_s, FALSE, FALSE,
4588 EL_NUT, ACTION_FALLING, -1
4591 Ynut_sB, FALSE, TRUE,
4592 EL_NUT, ACTION_FALLING, -1
4595 Ynut_e, FALSE, FALSE,
4596 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4599 Ynut_eB, FALSE, TRUE,
4600 EL_NUT, ACTION_MOVING, MV_BIT_RIGHT
4603 Ynut_w, FALSE, FALSE,
4604 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4607 Ynut_wB, FALSE, TRUE,
4608 EL_NUT, ACTION_MOVING, MV_BIT_LEFT
4611 Xbug_n, TRUE, FALSE,
4615 Xbug_e, TRUE, FALSE,
4616 EL_BUG_RIGHT, -1, -1
4619 Xbug_s, TRUE, FALSE,
4623 Xbug_w, TRUE, FALSE,
4627 Xbug_gon, FALSE, FALSE,
4631 Xbug_goe, FALSE, FALSE,
4632 EL_BUG_RIGHT, -1, -1
4635 Xbug_gos, FALSE, FALSE,
4639 Xbug_gow, FALSE, FALSE,
4643 Ybug_n, FALSE, FALSE,
4644 EL_BUG, ACTION_MOVING, MV_BIT_UP
4647 Ybug_nB, FALSE, TRUE,
4648 EL_BUG, ACTION_MOVING, MV_BIT_UP
4651 Ybug_e, FALSE, FALSE,
4652 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4655 Ybug_eB, FALSE, TRUE,
4656 EL_BUG, ACTION_MOVING, MV_BIT_RIGHT
4659 Ybug_s, FALSE, FALSE,
4660 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4663 Ybug_sB, FALSE, TRUE,
4664 EL_BUG, ACTION_MOVING, MV_BIT_DOWN
4667 Ybug_w, FALSE, FALSE,
4668 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4671 Ybug_wB, FALSE, TRUE,
4672 EL_BUG, ACTION_MOVING, MV_BIT_LEFT
4675 Ybug_w_n, FALSE, FALSE,
4676 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4679 Ybug_n_e, FALSE, FALSE,
4680 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4683 Ybug_e_s, FALSE, FALSE,
4684 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4687 Ybug_s_w, FALSE, FALSE,
4688 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4691 Ybug_e_n, FALSE, FALSE,
4692 EL_BUG, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4695 Ybug_s_e, FALSE, FALSE,
4696 EL_BUG, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4699 Ybug_w_s, FALSE, FALSE,
4700 EL_BUG, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4703 Ybug_n_w, FALSE, FALSE,
4704 EL_BUG, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4707 Ybug_stone, FALSE, FALSE,
4708 EL_BUG, ACTION_SMASHED_BY_ROCK, -1
4711 Ybug_spring, FALSE, FALSE,
4712 EL_BUG, ACTION_SMASHED_BY_SPRING, -1
4715 Xtank_n, TRUE, FALSE,
4716 EL_SPACESHIP_UP, -1, -1
4719 Xtank_e, TRUE, FALSE,
4720 EL_SPACESHIP_RIGHT, -1, -1
4723 Xtank_s, TRUE, FALSE,
4724 EL_SPACESHIP_DOWN, -1, -1
4727 Xtank_w, TRUE, FALSE,
4728 EL_SPACESHIP_LEFT, -1, -1
4731 Xtank_gon, FALSE, FALSE,
4732 EL_SPACESHIP_UP, -1, -1
4735 Xtank_goe, FALSE, FALSE,
4736 EL_SPACESHIP_RIGHT, -1, -1
4739 Xtank_gos, FALSE, FALSE,
4740 EL_SPACESHIP_DOWN, -1, -1
4743 Xtank_gow, FALSE, FALSE,
4744 EL_SPACESHIP_LEFT, -1, -1
4747 Ytank_n, FALSE, FALSE,
4748 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4751 Ytank_nB, FALSE, TRUE,
4752 EL_SPACESHIP, ACTION_MOVING, MV_BIT_UP
4755 Ytank_e, FALSE, FALSE,
4756 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4759 Ytank_eB, FALSE, TRUE,
4760 EL_SPACESHIP, ACTION_MOVING, MV_BIT_RIGHT
4763 Ytank_s, FALSE, FALSE,
4764 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4767 Ytank_sB, FALSE, TRUE,
4768 EL_SPACESHIP, ACTION_MOVING, MV_BIT_DOWN
4771 Ytank_w, FALSE, FALSE,
4772 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4775 Ytank_wB, FALSE, TRUE,
4776 EL_SPACESHIP, ACTION_MOVING, MV_BIT_LEFT
4779 Ytank_w_n, FALSE, FALSE,
4780 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_UP
4783 Ytank_n_e, FALSE, FALSE,
4784 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_RIGHT
4787 Ytank_e_s, FALSE, FALSE,
4788 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_DOWN
4791 Ytank_s_w, FALSE, FALSE,
4792 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_LEFT
4795 Ytank_e_n, FALSE, FALSE,
4796 EL_SPACESHIP, ACTION_TURNING_FROM_RIGHT, MV_BIT_UP
4799 Ytank_s_e, FALSE, FALSE,
4800 EL_SPACESHIP, ACTION_TURNING_FROM_DOWN, MV_BIT_RIGHT
4803 Ytank_w_s, FALSE, FALSE,
4804 EL_SPACESHIP, ACTION_TURNING_FROM_LEFT, MV_BIT_DOWN
4807 Ytank_n_w, FALSE, FALSE,
4808 EL_SPACESHIP, ACTION_TURNING_FROM_UP, MV_BIT_LEFT
4811 Ytank_stone, FALSE, FALSE,
4812 EL_SPACESHIP, ACTION_SMASHED_BY_ROCK, -1
4815 Ytank_spring, FALSE, FALSE,
4816 EL_SPACESHIP, ACTION_SMASHED_BY_SPRING, -1
4819 Xandroid, TRUE, FALSE,
4820 EL_EMC_ANDROID, ACTION_ACTIVE, -1
4823 Xandroid_1_n, FALSE, FALSE,
4824 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4827 Xandroid_2_n, FALSE, FALSE,
4828 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_UP
4831 Xandroid_1_e, FALSE, FALSE,
4832 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4835 Xandroid_2_e, FALSE, FALSE,
4836 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_RIGHT
4839 Xandroid_1_w, FALSE, FALSE,
4840 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4843 Xandroid_2_w, FALSE, FALSE,
4844 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_LEFT
4847 Xandroid_1_s, FALSE, FALSE,
4848 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4851 Xandroid_2_s, FALSE, FALSE,
4852 EL_EMC_ANDROID, ACTION_ACTIVE, MV_BIT_DOWN
4855 Yandroid_n, FALSE, FALSE,
4856 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4859 Yandroid_nB, FALSE, TRUE,
4860 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_UP
4863 Yandroid_ne, FALSE, FALSE,
4864 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPRIGHT
4867 Yandroid_neB, FALSE, TRUE,
4868 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPRIGHT
4871 Yandroid_e, FALSE, FALSE,
4872 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4875 Yandroid_eB, FALSE, TRUE,
4876 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_RIGHT
4879 Yandroid_se, FALSE, FALSE,
4880 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNRIGHT
4883 Yandroid_seB, FALSE, TRUE,
4884 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNRIGHT
4887 Yandroid_s, FALSE, FALSE,
4888 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4891 Yandroid_sB, FALSE, TRUE,
4892 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_DOWN
4895 Yandroid_sw, FALSE, FALSE,
4896 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_DOWNLEFT
4899 Yandroid_swB, FALSE, TRUE,
4900 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_DOWNLEFT
4903 Yandroid_w, FALSE, FALSE,
4904 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4907 Yandroid_wB, FALSE, TRUE,
4908 EL_EMC_ANDROID, ACTION_MOVING, MV_BIT_LEFT
4911 Yandroid_nw, FALSE, FALSE,
4912 EL_EMC_ANDROID, ACTION_GROWING, MV_BIT_UPLEFT
4915 Yandroid_nwB, FALSE, TRUE,
4916 EL_EMC_ANDROID, ACTION_SHRINKING, MV_BIT_UPLEFT
4919 Xspring, TRUE, FALSE,
4923 Xspring_pause, FALSE, FALSE,
4927 Xspring_e, FALSE, FALSE,
4931 Xspring_w, FALSE, FALSE,
4935 Xspring_fall, FALSE, FALSE,
4939 Yspring_s, FALSE, FALSE,
4940 EL_SPRING, ACTION_FALLING, -1
4943 Yspring_sB, FALSE, TRUE,
4944 EL_SPRING, ACTION_FALLING, -1
4947 Yspring_e, FALSE, FALSE,
4948 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4951 Yspring_eB, FALSE, TRUE,
4952 EL_SPRING, ACTION_MOVING, MV_BIT_RIGHT
4955 Yspring_w, FALSE, FALSE,
4956 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4959 Yspring_wB, FALSE, TRUE,
4960 EL_SPRING, ACTION_MOVING, MV_BIT_LEFT
4963 Yspring_kill_e, FALSE, FALSE,
4964 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4967 Yspring_kill_eB, FALSE, TRUE,
4968 EL_SPRING, ACTION_EATING, MV_BIT_RIGHT
4971 Yspring_kill_w, FALSE, FALSE,
4972 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4975 Yspring_kill_wB, FALSE, TRUE,
4976 EL_SPRING, ACTION_EATING, MV_BIT_LEFT
4979 Xeater_n, TRUE, FALSE,
4980 EL_YAMYAM_UP, -1, -1
4983 Xeater_e, TRUE, FALSE,
4984 EL_YAMYAM_RIGHT, -1, -1
4987 Xeater_w, TRUE, FALSE,
4988 EL_YAMYAM_LEFT, -1, -1
4991 Xeater_s, TRUE, FALSE,
4992 EL_YAMYAM_DOWN, -1, -1
4995 Yeater_n, FALSE, FALSE,
4996 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
4999 Yeater_nB, FALSE, TRUE,
5000 EL_YAMYAM, ACTION_MOVING, MV_BIT_UP
5003 Yeater_e, FALSE, FALSE,
5004 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5007 Yeater_eB, FALSE, TRUE,
5008 EL_YAMYAM, ACTION_MOVING, MV_BIT_RIGHT
5011 Yeater_s, FALSE, FALSE,
5012 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5015 Yeater_sB, FALSE, TRUE,
5016 EL_YAMYAM, ACTION_MOVING, MV_BIT_DOWN
5019 Yeater_w, FALSE, FALSE,
5020 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5023 Yeater_wB, FALSE, TRUE,
5024 EL_YAMYAM, ACTION_MOVING, MV_BIT_LEFT
5027 Yeater_stone, FALSE, FALSE,
5028 EL_YAMYAM, ACTION_SMASHED_BY_ROCK, -1
5031 Yeater_spring, FALSE, FALSE,
5032 EL_YAMYAM, ACTION_SMASHED_BY_SPRING, -1
5035 Xalien, TRUE, FALSE,
5039 Xalien_pause, FALSE, FALSE,
5043 Yalien_n, FALSE, FALSE,
5044 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5047 Yalien_nB, FALSE, TRUE,
5048 EL_ROBOT, ACTION_MOVING, MV_BIT_UP
5051 Yalien_e, FALSE, FALSE,
5052 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5055 Yalien_eB, FALSE, TRUE,
5056 EL_ROBOT, ACTION_MOVING, MV_BIT_RIGHT
5059 Yalien_s, FALSE, FALSE,
5060 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5063 Yalien_sB, FALSE, TRUE,
5064 EL_ROBOT, ACTION_MOVING, MV_BIT_DOWN
5067 Yalien_w, FALSE, FALSE,
5068 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5071 Yalien_wB, FALSE, TRUE,
5072 EL_ROBOT, ACTION_MOVING, MV_BIT_LEFT
5075 Yalien_stone, FALSE, FALSE,
5076 EL_ROBOT, ACTION_SMASHED_BY_ROCK, -1
5079 Yalien_spring, FALSE, FALSE,
5080 EL_ROBOT, ACTION_SMASHED_BY_SPRING, -1
5083 Xemerald, TRUE, FALSE,
5087 Xemerald_pause, FALSE, FALSE,
5091 Xemerald_fall, FALSE, FALSE,
5095 Xemerald_shine, FALSE, FALSE,
5096 EL_EMERALD, ACTION_TWINKLING, -1
5099 Yemerald_s, FALSE, FALSE,
5100 EL_EMERALD, ACTION_FALLING, -1
5103 Yemerald_sB, FALSE, TRUE,
5104 EL_EMERALD, ACTION_FALLING, -1
5107 Yemerald_e, FALSE, FALSE,
5108 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5111 Yemerald_eB, FALSE, TRUE,
5112 EL_EMERALD, ACTION_MOVING, MV_BIT_RIGHT
5115 Yemerald_w, FALSE, FALSE,
5116 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5119 Yemerald_wB, FALSE, TRUE,
5120 EL_EMERALD, ACTION_MOVING, MV_BIT_LEFT
5123 Yemerald_eat, FALSE, FALSE,
5124 EL_EMERALD, ACTION_COLLECTING, -1
5127 Yemerald_stone, FALSE, FALSE,
5128 EL_NUT, ACTION_BREAKING, -1
5131 Xdiamond, TRUE, FALSE,
5135 Xdiamond_pause, FALSE, FALSE,
5139 Xdiamond_fall, FALSE, FALSE,
5143 Xdiamond_shine, FALSE, FALSE,
5144 EL_DIAMOND, ACTION_TWINKLING, -1
5147 Ydiamond_s, FALSE, FALSE,
5148 EL_DIAMOND, ACTION_FALLING, -1
5151 Ydiamond_sB, FALSE, TRUE,
5152 EL_DIAMOND, ACTION_FALLING, -1
5155 Ydiamond_e, FALSE, FALSE,
5156 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5159 Ydiamond_eB, FALSE, TRUE,
5160 EL_DIAMOND, ACTION_MOVING, MV_BIT_RIGHT
5163 Ydiamond_w, FALSE, FALSE,
5164 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5167 Ydiamond_wB, FALSE, TRUE,
5168 EL_DIAMOND, ACTION_MOVING, MV_BIT_LEFT
5171 Ydiamond_eat, FALSE, FALSE,
5172 EL_DIAMOND, ACTION_COLLECTING, -1
5175 Ydiamond_stone, FALSE, FALSE,
5176 EL_DIAMOND, ACTION_SMASHED_BY_ROCK, -1
5179 Xdrip_fall, TRUE, FALSE,
5180 EL_AMOEBA_DROP, -1, -1
5183 Xdrip_stretch, FALSE, FALSE,
5184 EL_AMOEBA_DROP, ACTION_FALLING, -1
5187 Xdrip_stretchB, FALSE, TRUE,
5188 EL_AMOEBA_DROP, ACTION_FALLING, -1
5191 Xdrip_eat, FALSE, FALSE,
5192 EL_AMOEBA_DROP, ACTION_GROWING, -1
5195 Ydrip_s1, FALSE, FALSE,
5196 EL_AMOEBA_DROP, ACTION_FALLING, -1
5199 Ydrip_s1B, FALSE, TRUE,
5200 EL_AMOEBA_DROP, ACTION_FALLING, -1
5203 Ydrip_s2, FALSE, FALSE,
5204 EL_AMOEBA_DROP, ACTION_FALLING, -1
5207 Ydrip_s2B, FALSE, TRUE,
5208 EL_AMOEBA_DROP, ACTION_FALLING, -1
5215 Xbomb_pause, FALSE, FALSE,
5219 Xbomb_fall, FALSE, FALSE,
5223 Ybomb_s, FALSE, FALSE,
5224 EL_BOMB, ACTION_FALLING, -1
5227 Ybomb_sB, FALSE, TRUE,
5228 EL_BOMB, ACTION_FALLING, -1
5231 Ybomb_e, FALSE, FALSE,
5232 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5235 Ybomb_eB, FALSE, TRUE,
5236 EL_BOMB, ACTION_MOVING, MV_BIT_RIGHT
5239 Ybomb_w, FALSE, FALSE,
5240 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5243 Ybomb_wB, FALSE, TRUE,
5244 EL_BOMB, ACTION_MOVING, MV_BIT_LEFT
5247 Ybomb_eat, FALSE, FALSE,
5248 EL_BOMB, ACTION_ACTIVATING, -1
5251 Xballoon, TRUE, FALSE,
5255 Yballoon_n, FALSE, FALSE,
5256 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5259 Yballoon_nB, FALSE, TRUE,
5260 EL_BALLOON, ACTION_MOVING, MV_BIT_UP
5263 Yballoon_e, FALSE, FALSE,
5264 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5267 Yballoon_eB, FALSE, TRUE,
5268 EL_BALLOON, ACTION_MOVING, MV_BIT_RIGHT
5271 Yballoon_s, FALSE, FALSE,
5272 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5275 Yballoon_sB, FALSE, TRUE,
5276 EL_BALLOON, ACTION_MOVING, MV_BIT_DOWN
5279 Yballoon_w, FALSE, FALSE,
5280 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5283 Yballoon_wB, FALSE, TRUE,
5284 EL_BALLOON, ACTION_MOVING, MV_BIT_LEFT
5287 Xgrass, TRUE, FALSE,
5288 EL_EMC_GRASS, -1, -1
5291 Ygrass_nB, FALSE, FALSE,
5292 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_UP
5295 Ygrass_eB, FALSE, FALSE,
5296 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_RIGHT
5299 Ygrass_sB, FALSE, FALSE,
5300 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_DOWN
5303 Ygrass_wB, FALSE, FALSE,
5304 EL_EMC_GRASS, ACTION_DIGGING, MV_BIT_LEFT
5311 Ydirt_nB, FALSE, FALSE,
5312 EL_SAND, ACTION_DIGGING, MV_BIT_UP
5315 Ydirt_eB, FALSE, FALSE,
5316 EL_SAND, ACTION_DIGGING, MV_BIT_RIGHT
5319 Ydirt_sB, FALSE, FALSE,
5320 EL_SAND, ACTION_DIGGING, MV_BIT_DOWN
5323 Ydirt_wB, FALSE, FALSE,
5324 EL_SAND, ACTION_DIGGING, MV_BIT_LEFT
5327 Xacid_ne, TRUE, FALSE,
5328 EL_ACID_POOL_TOPRIGHT, -1, -1
5331 Xacid_se, TRUE, FALSE,
5332 EL_ACID_POOL_BOTTOMRIGHT, -1, -1
5335 Xacid_s, TRUE, FALSE,
5336 EL_ACID_POOL_BOTTOM, -1, -1
5339 Xacid_sw, TRUE, FALSE,
5340 EL_ACID_POOL_BOTTOMLEFT, -1, -1
5343 Xacid_nw, TRUE, FALSE,
5344 EL_ACID_POOL_TOPLEFT, -1, -1
5347 Xacid_1, TRUE, FALSE,
5351 Xacid_2, FALSE, FALSE,
5355 Xacid_3, FALSE, FALSE,
5359 Xacid_4, FALSE, FALSE,
5363 Xacid_5, FALSE, FALSE,
5367 Xacid_6, FALSE, FALSE,
5371 Xacid_7, FALSE, FALSE,
5375 Xacid_8, FALSE, FALSE,
5379 Xball_1, TRUE, FALSE,
5380 EL_EMC_MAGIC_BALL, -1, -1
5383 Xball_1B, FALSE, FALSE,
5384 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5387 Xball_2, FALSE, FALSE,
5388 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5391 Xball_2B, FALSE, FALSE,
5392 EL_EMC_MAGIC_BALL, ACTION_ACTIVE, -1
5395 Yball_eat, FALSE, FALSE,
5396 EL_EMC_MAGIC_BALL, ACTION_DROPPING, -1
5399 Ykey_1_eat, FALSE, FALSE,
5400 EL_EM_KEY_1, ACTION_COLLECTING, -1
5403 Ykey_2_eat, FALSE, FALSE,
5404 EL_EM_KEY_2, ACTION_COLLECTING, -1
5407 Ykey_3_eat, FALSE, FALSE,
5408 EL_EM_KEY_3, ACTION_COLLECTING, -1
5411 Ykey_4_eat, FALSE, FALSE,
5412 EL_EM_KEY_4, ACTION_COLLECTING, -1
5415 Ykey_5_eat, FALSE, FALSE,
5416 EL_EMC_KEY_5, ACTION_COLLECTING, -1
5419 Ykey_6_eat, FALSE, FALSE,
5420 EL_EMC_KEY_6, ACTION_COLLECTING, -1
5423 Ykey_7_eat, FALSE, FALSE,
5424 EL_EMC_KEY_7, ACTION_COLLECTING, -1
5427 Ykey_8_eat, FALSE, FALSE,
5428 EL_EMC_KEY_8, ACTION_COLLECTING, -1
5431 Ylenses_eat, FALSE, FALSE,
5432 EL_EMC_LENSES, ACTION_COLLECTING, -1
5435 Ymagnify_eat, FALSE, FALSE,
5436 EL_EMC_MAGNIFIER, ACTION_COLLECTING, -1
5439 Ygrass_eat, FALSE, FALSE,
5440 EL_EMC_GRASS, ACTION_SNAPPING, -1
5443 Ydirt_eat, FALSE, FALSE,
5444 EL_SAND, ACTION_SNAPPING, -1
5447 Xgrow_ns, TRUE, FALSE,
5448 EL_EXPANDABLE_WALL_VERTICAL, -1, -1
5451 Ygrow_ns_eat, FALSE, FALSE,
5452 EL_EXPANDABLE_WALL_VERTICAL, ACTION_GROWING, -1
5455 Xgrow_ew, TRUE, FALSE,
5456 EL_EXPANDABLE_WALL_HORIZONTAL, -1, -1
5459 Ygrow_ew_eat, FALSE, FALSE,
5460 EL_EXPANDABLE_WALL_HORIZONTAL, ACTION_GROWING, -1
5463 Xwonderwall, TRUE, FALSE,
5464 EL_MAGIC_WALL, -1, -1
5467 XwonderwallB, FALSE, FALSE,
5468 EL_MAGIC_WALL, ACTION_ACTIVE, -1
5471 Xamoeba_1, TRUE, FALSE,
5472 EL_AMOEBA_DRY, ACTION_OTHER, -1
5475 Xamoeba_2, FALSE, FALSE,
5476 EL_AMOEBA_DRY, ACTION_OTHER, -1
5479 Xamoeba_3, FALSE, FALSE,
5480 EL_AMOEBA_DRY, ACTION_OTHER, -1
5483 Xamoeba_4, FALSE, FALSE,
5484 EL_AMOEBA_DRY, ACTION_OTHER, -1
5487 Xamoeba_5, TRUE, FALSE,
5488 EL_AMOEBA_WET, ACTION_OTHER, -1
5491 Xamoeba_6, FALSE, FALSE,
5492 EL_AMOEBA_WET, ACTION_OTHER, -1
5495 Xamoeba_7, FALSE, FALSE,
5496 EL_AMOEBA_WET, ACTION_OTHER, -1
5499 Xamoeba_8, FALSE, FALSE,
5500 EL_AMOEBA_WET, ACTION_OTHER, -1
5503 Xdoor_1, TRUE, FALSE,
5504 EL_EM_GATE_1, -1, -1
5507 Xdoor_2, TRUE, FALSE,
5508 EL_EM_GATE_2, -1, -1
5511 Xdoor_3, TRUE, FALSE,
5512 EL_EM_GATE_3, -1, -1
5515 Xdoor_4, TRUE, FALSE,
5516 EL_EM_GATE_4, -1, -1
5519 Xdoor_5, TRUE, FALSE,
5520 EL_EMC_GATE_5, -1, -1
5523 Xdoor_6, TRUE, FALSE,
5524 EL_EMC_GATE_6, -1, -1
5527 Xdoor_7, TRUE, FALSE,
5528 EL_EMC_GATE_7, -1, -1
5531 Xdoor_8, TRUE, FALSE,
5532 EL_EMC_GATE_8, -1, -1
5535 Xkey_1, TRUE, FALSE,
5539 Xkey_2, TRUE, FALSE,
5543 Xkey_3, TRUE, FALSE,
5547 Xkey_4, TRUE, FALSE,
5551 Xkey_5, TRUE, FALSE,
5552 EL_EMC_KEY_5, -1, -1
5555 Xkey_6, TRUE, FALSE,
5556 EL_EMC_KEY_6, -1, -1
5559 Xkey_7, TRUE, FALSE,
5560 EL_EMC_KEY_7, -1, -1
5563 Xkey_8, TRUE, FALSE,
5564 EL_EMC_KEY_8, -1, -1
5567 Xwind_n, TRUE, FALSE,
5568 EL_BALLOON_SWITCH_UP, -1, -1
5571 Xwind_e, TRUE, FALSE,
5572 EL_BALLOON_SWITCH_RIGHT, -1, -1
5575 Xwind_s, TRUE, FALSE,
5576 EL_BALLOON_SWITCH_DOWN, -1, -1
5579 Xwind_w, TRUE, FALSE,
5580 EL_BALLOON_SWITCH_LEFT, -1, -1
5583 Xwind_nesw, TRUE, FALSE,
5584 EL_BALLOON_SWITCH_ANY, -1, -1
5587 Xwind_stop, TRUE, FALSE,
5588 EL_BALLOON_SWITCH_NONE, -1, -1
5592 EL_EM_EXIT_CLOSED, -1, -1
5595 Xexit_1, TRUE, FALSE,
5596 EL_EM_EXIT_OPEN, -1, -1
5599 Xexit_2, FALSE, FALSE,
5600 EL_EM_EXIT_OPEN, -1, -1
5603 Xexit_3, FALSE, FALSE,
5604 EL_EM_EXIT_OPEN, -1, -1
5607 Xdynamite, TRUE, FALSE,
5608 EL_EM_DYNAMITE, -1, -1
5611 Ydynamite_eat, FALSE, FALSE,
5612 EL_EM_DYNAMITE, ACTION_COLLECTING, -1
5615 Xdynamite_1, TRUE, FALSE,
5616 EL_EM_DYNAMITE_ACTIVE, -1, -1
5619 Xdynamite_2, FALSE, FALSE,
5620 EL_EM_DYNAMITE_ACTIVE, -1, -1
5623 Xdynamite_3, FALSE, FALSE,
5624 EL_EM_DYNAMITE_ACTIVE, -1, -1
5627 Xdynamite_4, FALSE, FALSE,
5628 EL_EM_DYNAMITE_ACTIVE, -1, -1
5631 Xbumper, TRUE, FALSE,
5632 EL_EMC_SPRING_BUMPER, -1, -1
5635 XbumperB, FALSE, FALSE,
5636 EL_EMC_SPRING_BUMPER, ACTION_ACTIVE, -1
5639 Xwheel, TRUE, FALSE,
5640 EL_ROBOT_WHEEL, -1, -1
5643 XwheelB, FALSE, FALSE,
5644 EL_ROBOT_WHEEL, ACTION_ACTIVE, -1
5647 Xswitch, TRUE, FALSE,
5648 EL_EMC_MAGIC_BALL_SWITCH, -1, -1
5651 XswitchB, FALSE, FALSE,
5652 EL_EMC_MAGIC_BALL_SWITCH, ACTION_ACTIVE, -1
5656 EL_QUICKSAND_EMPTY, -1, -1
5659 Xsand_stone, TRUE, FALSE,
5660 EL_QUICKSAND_FULL, -1, -1
5663 Xsand_stonein_1, FALSE, TRUE,
5664 EL_ROCK, ACTION_FILLING, -1
5667 Xsand_stonein_2, FALSE, TRUE,
5668 EL_ROCK, ACTION_FILLING, -1
5671 Xsand_stonein_3, FALSE, TRUE,
5672 EL_ROCK, ACTION_FILLING, -1
5675 Xsand_stonein_4, FALSE, TRUE,
5676 EL_ROCK, ACTION_FILLING, -1
5679 Xsand_stonesand_1, FALSE, FALSE,
5680 EL_QUICKSAND_EMPTYING, -1, -1
5683 Xsand_stonesand_2, FALSE, FALSE,
5684 EL_QUICKSAND_EMPTYING, -1, -1
5687 Xsand_stonesand_3, FALSE, FALSE,
5688 EL_QUICKSAND_EMPTYING, -1, -1
5691 Xsand_stonesand_4, FALSE, FALSE,
5692 EL_QUICKSAND_EMPTYING, -1, -1
5695 Xsand_stonesand_quickout_1, FALSE, FALSE,
5696 EL_QUICKSAND_EMPTYING, -1, -1
5699 Xsand_stonesand_quickout_2, FALSE, FALSE,
5700 EL_QUICKSAND_EMPTYING, -1, -1
5703 Xsand_stoneout_1, FALSE, FALSE,
5704 EL_ROCK, ACTION_EMPTYING, -1
5707 Xsand_stoneout_2, FALSE, FALSE,
5708 EL_ROCK, ACTION_EMPTYING, -1
5711 Xsand_sandstone_1, FALSE, FALSE,
5712 EL_QUICKSAND_FILLING, -1, -1
5715 Xsand_sandstone_2, FALSE, FALSE,
5716 EL_QUICKSAND_FILLING, -1, -1
5719 Xsand_sandstone_3, FALSE, FALSE,
5720 EL_QUICKSAND_FILLING, -1, -1
5723 Xsand_sandstone_4, FALSE, FALSE,
5724 EL_QUICKSAND_FILLING, -1, -1
5727 Xplant, TRUE, FALSE,
5728 EL_EMC_PLANT, -1, -1
5731 Yplant, FALSE, FALSE,
5732 EL_EMC_PLANT, -1, -1
5735 Xlenses, TRUE, FALSE,
5736 EL_EMC_LENSES, -1, -1
5739 Xmagnify, TRUE, FALSE,
5740 EL_EMC_MAGNIFIER, -1, -1
5743 Xdripper, TRUE, FALSE,
5744 EL_EMC_DRIPPER, -1, -1
5747 XdripperB, FALSE, FALSE,
5748 EL_EMC_DRIPPER, ACTION_ACTIVE, -1
5751 Xfake_blank, TRUE, FALSE,
5752 EL_INVISIBLE_WALL, -1, -1
5755 Xfake_blankB, FALSE, FALSE,
5756 EL_INVISIBLE_WALL, ACTION_ACTIVE, -1
5759 Xfake_grass, TRUE, FALSE,
5760 EL_EMC_FAKE_GRASS, -1, -1
5763 Xfake_grassB, FALSE, FALSE,
5764 EL_EMC_FAKE_GRASS, ACTION_ACTIVE, -1
5767 Xfake_door_1, TRUE, FALSE,
5768 EL_EM_GATE_1_GRAY, -1, -1
5771 Xfake_door_2, TRUE, FALSE,
5772 EL_EM_GATE_2_GRAY, -1, -1
5775 Xfake_door_3, TRUE, FALSE,
5776 EL_EM_GATE_3_GRAY, -1, -1
5779 Xfake_door_4, TRUE, FALSE,
5780 EL_EM_GATE_4_GRAY, -1, -1
5783 Xfake_door_5, TRUE, FALSE,
5784 EL_EMC_GATE_5_GRAY, -1, -1
5787 Xfake_door_6, TRUE, FALSE,
5788 EL_EMC_GATE_6_GRAY, -1, -1
5791 Xfake_door_7, TRUE, FALSE,
5792 EL_EMC_GATE_7_GRAY, -1, -1
5795 Xfake_door_8, TRUE, FALSE,
5796 EL_EMC_GATE_8_GRAY, -1, -1
5799 Xfake_acid_1, TRUE, FALSE,
5800 EL_EMC_FAKE_ACID, -1, -1
5803 Xfake_acid_2, FALSE, FALSE,
5804 EL_EMC_FAKE_ACID, -1, -1
5807 Xfake_acid_3, FALSE, FALSE,
5808 EL_EMC_FAKE_ACID, -1, -1
5811 Xfake_acid_4, FALSE, FALSE,
5812 EL_EMC_FAKE_ACID, -1, -1
5815 Xfake_acid_5, FALSE, FALSE,
5816 EL_EMC_FAKE_ACID, -1, -1
5819 Xfake_acid_6, FALSE, FALSE,
5820 EL_EMC_FAKE_ACID, -1, -1
5823 Xfake_acid_7, FALSE, FALSE,
5824 EL_EMC_FAKE_ACID, -1, -1
5827 Xfake_acid_8, FALSE, FALSE,
5828 EL_EMC_FAKE_ACID, -1, -1
5831 Xsteel_1, TRUE, FALSE,
5832 EL_STEELWALL, -1, -1
5835 Xsteel_2, TRUE, FALSE,
5836 EL_EMC_STEELWALL_2, -1, -1
5839 Xsteel_3, TRUE, FALSE,
5840 EL_EMC_STEELWALL_3, -1, -1
5843 Xsteel_4, TRUE, FALSE,
5844 EL_EMC_STEELWALL_4, -1, -1
5847 Xwall_1, TRUE, FALSE,
5851 Xwall_2, TRUE, FALSE,
5852 EL_EMC_WALL_14, -1, -1
5855 Xwall_3, TRUE, FALSE,
5856 EL_EMC_WALL_15, -1, -1
5859 Xwall_4, TRUE, FALSE,
5860 EL_EMC_WALL_16, -1, -1
5863 Xround_wall_1, TRUE, FALSE,
5864 EL_WALL_SLIPPERY, -1, -1
5867 Xround_wall_2, TRUE, FALSE,
5868 EL_EMC_WALL_SLIPPERY_2, -1, -1
5871 Xround_wall_3, TRUE, FALSE,
5872 EL_EMC_WALL_SLIPPERY_3, -1, -1
5875 Xround_wall_4, TRUE, FALSE,
5876 EL_EMC_WALL_SLIPPERY_4, -1, -1
5879 Xdecor_1, TRUE, FALSE,
5880 EL_EMC_WALL_8, -1, -1
5883 Xdecor_2, TRUE, FALSE,
5884 EL_EMC_WALL_6, -1, -1
5887 Xdecor_3, TRUE, FALSE,
5888 EL_EMC_WALL_4, -1, -1
5891 Xdecor_4, TRUE, FALSE,
5892 EL_EMC_WALL_7, -1, -1
5895 Xdecor_5, TRUE, FALSE,
5896 EL_EMC_WALL_5, -1, -1
5899 Xdecor_6, TRUE, FALSE,
5900 EL_EMC_WALL_9, -1, -1
5903 Xdecor_7, TRUE, FALSE,
5904 EL_EMC_WALL_10, -1, -1
5907 Xdecor_8, TRUE, FALSE,
5908 EL_EMC_WALL_1, -1, -1
5911 Xdecor_9, TRUE, FALSE,
5912 EL_EMC_WALL_2, -1, -1
5915 Xdecor_10, TRUE, FALSE,
5916 EL_EMC_WALL_3, -1, -1
5919 Xdecor_11, TRUE, FALSE,
5920 EL_EMC_WALL_11, -1, -1
5923 Xdecor_12, TRUE, FALSE,
5924 EL_EMC_WALL_12, -1, -1
5927 Xalpha_0, TRUE, FALSE,
5928 EL_CHAR('0'), -1, -1
5931 Xalpha_1, TRUE, FALSE,
5932 EL_CHAR('1'), -1, -1
5935 Xalpha_2, TRUE, FALSE,
5936 EL_CHAR('2'), -1, -1
5939 Xalpha_3, TRUE, FALSE,
5940 EL_CHAR('3'), -1, -1
5943 Xalpha_4, TRUE, FALSE,
5944 EL_CHAR('4'), -1, -1
5947 Xalpha_5, TRUE, FALSE,
5948 EL_CHAR('5'), -1, -1
5951 Xalpha_6, TRUE, FALSE,
5952 EL_CHAR('6'), -1, -1
5955 Xalpha_7, TRUE, FALSE,
5956 EL_CHAR('7'), -1, -1
5959 Xalpha_8, TRUE, FALSE,
5960 EL_CHAR('8'), -1, -1
5963 Xalpha_9, TRUE, FALSE,
5964 EL_CHAR('9'), -1, -1
5967 Xalpha_excla, TRUE, FALSE,
5968 EL_CHAR('!'), -1, -1
5971 Xalpha_quote, TRUE, FALSE,
5972 EL_CHAR('"'), -1, -1
5975 Xalpha_comma, TRUE, FALSE,
5976 EL_CHAR(','), -1, -1
5979 Xalpha_minus, TRUE, FALSE,
5980 EL_CHAR('-'), -1, -1
5983 Xalpha_perio, TRUE, FALSE,
5984 EL_CHAR('.'), -1, -1
5987 Xalpha_colon, TRUE, FALSE,
5988 EL_CHAR(':'), -1, -1
5991 Xalpha_quest, TRUE, FALSE,
5992 EL_CHAR('?'), -1, -1
5995 Xalpha_a, TRUE, FALSE,
5996 EL_CHAR('A'), -1, -1
5999 Xalpha_b, TRUE, FALSE,
6000 EL_CHAR('B'), -1, -1
6003 Xalpha_c, TRUE, FALSE,
6004 EL_CHAR('C'), -1, -1
6007 Xalpha_d, TRUE, FALSE,
6008 EL_CHAR('D'), -1, -1
6011 Xalpha_e, TRUE, FALSE,
6012 EL_CHAR('E'), -1, -1
6015 Xalpha_f, TRUE, FALSE,
6016 EL_CHAR('F'), -1, -1
6019 Xalpha_g, TRUE, FALSE,
6020 EL_CHAR('G'), -1, -1
6023 Xalpha_h, TRUE, FALSE,
6024 EL_CHAR('H'), -1, -1
6027 Xalpha_i, TRUE, FALSE,
6028 EL_CHAR('I'), -1, -1
6031 Xalpha_j, TRUE, FALSE,
6032 EL_CHAR('J'), -1, -1
6035 Xalpha_k, TRUE, FALSE,
6036 EL_CHAR('K'), -1, -1
6039 Xalpha_l, TRUE, FALSE,
6040 EL_CHAR('L'), -1, -1
6043 Xalpha_m, TRUE, FALSE,
6044 EL_CHAR('M'), -1, -1
6047 Xalpha_n, TRUE, FALSE,
6048 EL_CHAR('N'), -1, -1
6051 Xalpha_o, TRUE, FALSE,
6052 EL_CHAR('O'), -1, -1
6055 Xalpha_p, TRUE, FALSE,
6056 EL_CHAR('P'), -1, -1
6059 Xalpha_q, TRUE, FALSE,
6060 EL_CHAR('Q'), -1, -1
6063 Xalpha_r, TRUE, FALSE,
6064 EL_CHAR('R'), -1, -1
6067 Xalpha_s, TRUE, FALSE,
6068 EL_CHAR('S'), -1, -1
6071 Xalpha_t, TRUE, FALSE,
6072 EL_CHAR('T'), -1, -1
6075 Xalpha_u, TRUE, FALSE,
6076 EL_CHAR('U'), -1, -1
6079 Xalpha_v, TRUE, FALSE,
6080 EL_CHAR('V'), -1, -1
6083 Xalpha_w, TRUE, FALSE,
6084 EL_CHAR('W'), -1, -1
6087 Xalpha_x, TRUE, FALSE,
6088 EL_CHAR('X'), -1, -1
6091 Xalpha_y, TRUE, FALSE,
6092 EL_CHAR('Y'), -1, -1
6095 Xalpha_z, TRUE, FALSE,
6096 EL_CHAR('Z'), -1, -1
6099 Xalpha_arrow_e, TRUE, FALSE,
6100 EL_CHAR('>'), -1, -1
6103 Xalpha_arrow_w, TRUE, FALSE,
6104 EL_CHAR('<'), -1, -1
6107 Xalpha_copyr, TRUE, FALSE,
6108 EL_CHAR(CHAR_BYTE_COPYRIGHT), -1, -1
6112 Xboom_bug, FALSE, FALSE,
6113 EL_BUG, ACTION_EXPLODING, -1
6116 Xboom_bomb, FALSE, FALSE,
6117 EL_BOMB, ACTION_EXPLODING, -1
6120 Xboom_android, FALSE, FALSE,
6121 EL_EMC_ANDROID, ACTION_OTHER, -1
6124 Xboom_1, FALSE, FALSE,
6125 EL_DEFAULT, ACTION_EXPLODING, -1
6128 Xboom_2, FALSE, FALSE,
6129 EL_DEFAULT, ACTION_EXPLODING, -1
6132 Znormal, FALSE, FALSE,
6136 Zdynamite, FALSE, FALSE,
6140 Zplayer, FALSE, FALSE,
6144 ZBORDER, FALSE, FALSE,
6154 static struct Mapping_EM_to_RND_player
6163 em_player_mapping_list[] =
6167 EL_PLAYER_1, ACTION_MOVING, MV_BIT_UP,
6171 EL_PLAYER_1, ACTION_MOVING, MV_BIT_RIGHT,
6175 EL_PLAYER_1, ACTION_MOVING, MV_BIT_DOWN,
6179 EL_PLAYER_1, ACTION_MOVING, MV_BIT_LEFT,
6183 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_UP,
6187 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_RIGHT,
6191 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_DOWN,
6195 EL_PLAYER_1, ACTION_PUSHING, MV_BIT_LEFT,
6199 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_UP,
6203 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_RIGHT,
6207 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_DOWN,
6211 EL_PLAYER_1, ACTION_SNAPPING, MV_BIT_LEFT,
6215 EL_PLAYER_2, ACTION_MOVING, MV_BIT_UP,
6219 EL_PLAYER_2, ACTION_MOVING, MV_BIT_RIGHT,
6223 EL_PLAYER_2, ACTION_MOVING, MV_BIT_DOWN,
6227 EL_PLAYER_2, ACTION_MOVING, MV_BIT_LEFT,
6231 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_UP,
6235 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_RIGHT,
6239 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_DOWN,
6243 EL_PLAYER_2, ACTION_PUSHING, MV_BIT_LEFT,
6247 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_UP,
6251 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_RIGHT,
6255 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_DOWN,
6259 EL_PLAYER_2, ACTION_SNAPPING, MV_BIT_LEFT,
6263 EL_PLAYER_1, ACTION_DEFAULT, -1,
6267 EL_PLAYER_2, ACTION_DEFAULT, -1,
6271 EL_PLAYER_3, ACTION_MOVING, MV_BIT_UP,
6275 EL_PLAYER_3, ACTION_MOVING, MV_BIT_RIGHT,
6279 EL_PLAYER_3, ACTION_MOVING, MV_BIT_DOWN,
6283 EL_PLAYER_3, ACTION_MOVING, MV_BIT_LEFT,
6287 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_UP,
6291 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_RIGHT,
6295 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_DOWN,
6299 EL_PLAYER_3, ACTION_PUSHING, MV_BIT_LEFT,
6303 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_UP,
6307 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_RIGHT,
6311 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_DOWN,
6315 EL_PLAYER_3, ACTION_SNAPPING, MV_BIT_LEFT,
6319 EL_PLAYER_4, ACTION_MOVING, MV_BIT_UP,
6323 EL_PLAYER_4, ACTION_MOVING, MV_BIT_RIGHT,
6327 EL_PLAYER_4, ACTION_MOVING, MV_BIT_DOWN,
6331 EL_PLAYER_4, ACTION_MOVING, MV_BIT_LEFT,
6335 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_UP,
6339 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_RIGHT,
6343 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_DOWN,
6347 EL_PLAYER_4, ACTION_PUSHING, MV_BIT_LEFT,
6351 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_UP,
6355 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_RIGHT,
6359 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_DOWN,
6363 EL_PLAYER_4, ACTION_SNAPPING, MV_BIT_LEFT,
6367 EL_PLAYER_3, ACTION_DEFAULT, -1,
6371 EL_PLAYER_4, ACTION_DEFAULT, -1,
6380 int map_element_RND_to_EM(int element_rnd)
6382 static unsigned short mapping_RND_to_EM[NUM_FILE_ELEMENTS];
6383 static boolean mapping_initialized = FALSE;
6385 if (!mapping_initialized)
6389 /* return "Xalpha_quest" for all undefined elements in mapping array */
6390 for (i = 0; i < NUM_FILE_ELEMENTS; i++)
6391 mapping_RND_to_EM[i] = Xalpha_quest;
6393 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6394 if (em_object_mapping_list[i].is_rnd_to_em_mapping)
6395 mapping_RND_to_EM[em_object_mapping_list[i].element_rnd] =
6396 em_object_mapping_list[i].element_em;
6398 mapping_initialized = TRUE;
6401 if (element_rnd >= 0 && element_rnd < NUM_FILE_ELEMENTS)
6402 return mapping_RND_to_EM[element_rnd];
6404 Error(ERR_WARN, "invalid RND level element %d", element_rnd);
6409 int map_element_EM_to_RND(int element_em)
6411 static unsigned short mapping_EM_to_RND[TILE_MAX];
6412 static boolean mapping_initialized = FALSE;
6414 if (!mapping_initialized)
6418 /* return "EL_UNKNOWN" for all undefined elements in mapping array */
6419 for (i = 0; i < TILE_MAX; i++)
6420 mapping_EM_to_RND[i] = EL_UNKNOWN;
6422 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
6423 mapping_EM_to_RND[em_object_mapping_list[i].element_em] =
6424 em_object_mapping_list[i].element_rnd;
6426 mapping_initialized = TRUE;
6429 if (element_em >= 0 && element_em < TILE_MAX)
6430 return mapping_EM_to_RND[element_em];
6432 Error(ERR_WARN, "invalid EM level element %d", element_em);
6437 void map_android_clone_elements_RND_to_EM(struct LevelInfo *level)
6439 struct LevelInfo_EM *level_em = level->native_em_level;
6440 struct LEVEL *lev = level_em->lev;
6443 for (i = 0; i < TILE_MAX; i++)
6444 lev->android_array[i] = Xblank;
6446 for (i = 0; i < level->num_android_clone_elements; i++)
6448 int element_rnd = level->android_clone_element[i];
6449 int element_em = map_element_RND_to_EM(element_rnd);
6451 for (j = 0; em_object_mapping_list[j].element_em != -1; j++)
6452 if (em_object_mapping_list[j].element_rnd == element_rnd)
6453 lev->android_array[em_object_mapping_list[j].element_em] = element_em;
6457 void map_android_clone_elements_EM_to_RND(struct LevelInfo *level)
6459 struct LevelInfo_EM *level_em = level->native_em_level;
6460 struct LEVEL *lev = level_em->lev;
6463 level->num_android_clone_elements = 0;
6465 for (i = 0; i < TILE_MAX; i++)
6467 int element_em = lev->android_array[i];
6469 boolean element_found = FALSE;
6471 if (element_em == Xblank)
6474 element_rnd = map_element_EM_to_RND(element_em);
6476 for (j = 0; j < level->num_android_clone_elements; j++)
6477 if (level->android_clone_element[j] == element_rnd)
6478 element_found = TRUE;
6482 level->android_clone_element[level->num_android_clone_elements++] =
6485 if (level->num_android_clone_elements == MAX_ANDROID_ELEMENTS)
6490 if (level->num_android_clone_elements == 0)
6492 level->num_android_clone_elements = 1;
6493 level->android_clone_element[0] = EL_EMPTY;
6497 int map_direction_RND_to_EM(int direction)
6499 return (direction == MV_UP ? 0 :
6500 direction == MV_RIGHT ? 1 :
6501 direction == MV_DOWN ? 2 :
6502 direction == MV_LEFT ? 3 :
6506 int map_direction_EM_to_RND(int direction)
6508 return (direction == 0 ? MV_UP :
6509 direction == 1 ? MV_RIGHT :
6510 direction == 2 ? MV_DOWN :
6511 direction == 3 ? MV_LEFT :
6515 int map_element_RND_to_SP(int element_rnd)
6517 int element_sp = 0x20; /* map unknown elements to yellow "hardware" */
6519 if (element_rnd >= EL_SP_START &&
6520 element_rnd <= EL_SP_END)
6521 element_sp = element_rnd - EL_SP_START;
6522 else if (element_rnd == EL_EMPTY_SPACE)
6524 else if (element_rnd == EL_INVISIBLE_WALL)
6530 int map_element_SP_to_RND(int element_sp)
6532 int element_rnd = EL_UNKNOWN;
6534 if (element_sp >= 0x00 &&
6536 element_rnd = EL_SP_START + element_sp;
6537 else if (element_sp == 0x28)
6538 element_rnd = EL_INVISIBLE_WALL;
6543 int map_action_SP_to_RND(int action_sp)
6547 case actActive: return ACTION_ACTIVE;
6548 case actImpact: return ACTION_IMPACT;
6549 case actExploding: return ACTION_EXPLODING;
6550 case actDigging: return ACTION_DIGGING;
6551 case actSnapping: return ACTION_SNAPPING;
6552 case actCollecting: return ACTION_COLLECTING;
6553 case actPassing: return ACTION_PASSING;
6554 case actPushing: return ACTION_PUSHING;
6555 case actDropping: return ACTION_DROPPING;
6557 default: return ACTION_DEFAULT;
6561 int get_next_element(int element)
6565 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
6566 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
6567 case EL_QUICKSAND_FAST_FILLING: return EL_QUICKSAND_FAST_FULL;
6568 case EL_QUICKSAND_FAST_EMPTYING: return EL_QUICKSAND_FAST_EMPTY;
6569 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
6570 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
6571 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
6572 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
6573 case EL_DC_MAGIC_WALL_FILLING: return EL_DC_MAGIC_WALL_FULL;
6574 case EL_DC_MAGIC_WALL_EMPTYING: return EL_DC_MAGIC_WALL_ACTIVE;
6575 case EL_AMOEBA_DROPPING: return EL_AMOEBA_WET;
6577 default: return element;
6581 int el_act_dir2img(int element, int action, int direction)
6583 element = GFX_ELEMENT(element);
6584 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6586 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6587 return element_info[element].direction_graphic[action][direction];
6590 static int el_act_dir2crm(int element, int action, int direction)
6592 element = GFX_ELEMENT(element);
6593 direction = MV_DIR_TO_BIT(direction); /* default: MV_NONE => MV_DOWN */
6595 /* direction_graphic[][] == graphic[] for undefined direction graphics */
6596 return element_info[element].direction_crumbled[action][direction];
6599 int el_act2img(int element, int action)
6601 element = GFX_ELEMENT(element);
6603 return element_info[element].graphic[action];
6606 int el_act2crm(int element, int action)
6608 element = GFX_ELEMENT(element);
6610 return element_info[element].crumbled[action];
6613 int el_dir2img(int element, int direction)
6615 element = GFX_ELEMENT(element);
6617 return el_act_dir2img(element, ACTION_DEFAULT, direction);
6620 int el2baseimg(int element)
6622 return element_info[element].graphic[ACTION_DEFAULT];
6625 int el2img(int element)
6627 element = GFX_ELEMENT(element);
6629 return element_info[element].graphic[ACTION_DEFAULT];
6632 int el2edimg(int element)
6634 element = GFX_ELEMENT(element);
6636 return element_info[element].special_graphic[GFX_SPECIAL_ARG_EDITOR];
6639 int el2preimg(int element)
6641 element = GFX_ELEMENT(element);
6643 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PREVIEW];
6646 int el2panelimg(int element)
6648 element = GFX_ELEMENT(element);
6650 return element_info[element].special_graphic[GFX_SPECIAL_ARG_PANEL];
6653 int font2baseimg(int font_nr)
6655 return font_info[font_nr].special_graphic[GFX_SPECIAL_ARG_DEFAULT];
6658 int getBeltNrFromBeltElement(int element)
6660 return (element < EL_CONVEYOR_BELT_2_LEFT ? 0 :
6661 element < EL_CONVEYOR_BELT_3_LEFT ? 1 :
6662 element < EL_CONVEYOR_BELT_4_LEFT ? 2 : 3);
6665 int getBeltNrFromBeltActiveElement(int element)
6667 return (element < EL_CONVEYOR_BELT_2_LEFT_ACTIVE ? 0 :
6668 element < EL_CONVEYOR_BELT_3_LEFT_ACTIVE ? 1 :
6669 element < EL_CONVEYOR_BELT_4_LEFT_ACTIVE ? 2 : 3);
6672 int getBeltNrFromBeltSwitchElement(int element)
6674 return (element < EL_CONVEYOR_BELT_2_SWITCH_LEFT ? 0 :
6675 element < EL_CONVEYOR_BELT_3_SWITCH_LEFT ? 1 :
6676 element < EL_CONVEYOR_BELT_4_SWITCH_LEFT ? 2 : 3);
6679 int getBeltDirNrFromBeltElement(int element)
6681 static int belt_base_element[4] =
6683 EL_CONVEYOR_BELT_1_LEFT,
6684 EL_CONVEYOR_BELT_2_LEFT,
6685 EL_CONVEYOR_BELT_3_LEFT,
6686 EL_CONVEYOR_BELT_4_LEFT
6689 int belt_nr = getBeltNrFromBeltElement(element);
6690 int belt_dir_nr = element - belt_base_element[belt_nr];
6692 return (belt_dir_nr % 3);
6695 int getBeltDirNrFromBeltSwitchElement(int element)
6697 static int belt_base_element[4] =
6699 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6700 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6701 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6702 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6705 int belt_nr = getBeltNrFromBeltSwitchElement(element);
6706 int belt_dir_nr = element - belt_base_element[belt_nr];
6708 return (belt_dir_nr % 3);
6711 int getBeltDirFromBeltElement(int element)
6713 static int belt_move_dir[3] =
6720 int belt_dir_nr = getBeltDirNrFromBeltElement(element);
6722 return belt_move_dir[belt_dir_nr];
6725 int getBeltDirFromBeltSwitchElement(int element)
6727 static int belt_move_dir[3] =
6734 int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(element);
6736 return belt_move_dir[belt_dir_nr];
6739 int getBeltElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6741 static int belt_base_element[4] =
6743 EL_CONVEYOR_BELT_1_LEFT,
6744 EL_CONVEYOR_BELT_2_LEFT,
6745 EL_CONVEYOR_BELT_3_LEFT,
6746 EL_CONVEYOR_BELT_4_LEFT
6749 return belt_base_element[belt_nr] + belt_dir_nr;
6752 int getBeltElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6754 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6756 return getBeltElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6759 int getBeltSwitchElementFromBeltNrAndBeltDirNr(int belt_nr, int belt_dir_nr)
6761 static int belt_base_element[4] =
6763 EL_CONVEYOR_BELT_1_SWITCH_LEFT,
6764 EL_CONVEYOR_BELT_2_SWITCH_LEFT,
6765 EL_CONVEYOR_BELT_3_SWITCH_LEFT,
6766 EL_CONVEYOR_BELT_4_SWITCH_LEFT
6769 return belt_base_element[belt_nr] + belt_dir_nr;
6772 int getBeltSwitchElementFromBeltNrAndBeltDir(int belt_nr, int belt_dir)
6774 int belt_dir_nr = (belt_dir == MV_LEFT ? 0 : belt_dir == MV_RIGHT ? 2 : 1);
6776 return getBeltSwitchElementFromBeltNrAndBeltDirNr(belt_nr, belt_dir_nr);
6779 boolean getTeamMode_EM()
6781 return game.team_mode;
6784 int getGameFrameDelay_EM(int native_em_game_frame_delay)
6786 int game_frame_delay_value;
6788 game_frame_delay_value =
6789 (tape.playing && tape.fast_forward ? FfwdFrameDelay :
6790 GameFrameDelay == GAME_FRAME_DELAY ? native_em_game_frame_delay :
6793 if (tape.playing && tape.warp_forward && !tape.pausing)
6794 game_frame_delay_value = 0;
6796 return game_frame_delay_value;
6799 unsigned int InitRND(int seed)
6801 if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
6802 return InitEngineRandom_EM(seed);
6803 else if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
6804 return InitEngineRandom_SP(seed);
6806 return InitEngineRandom_RND(seed);
6809 static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
6810 static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
6812 inline static int get_effective_element_EM(int tile, int frame_em)
6814 int element = object_mapping[tile].element_rnd;
6815 int action = object_mapping[tile].action;
6816 boolean is_backside = object_mapping[tile].is_backside;
6817 boolean action_removing = (action == ACTION_DIGGING ||
6818 action == ACTION_SNAPPING ||
6819 action == ACTION_COLLECTING);
6825 case Yacid_splash_eB:
6826 case Yacid_splash_wB:
6827 return (frame_em > 5 ? EL_EMPTY : element);
6833 else /* frame_em == 7 */
6837 case Yacid_splash_eB:
6838 case Yacid_splash_wB:
6841 case Yemerald_stone:
6844 case Ydiamond_stone:
6848 case Xdrip_stretchB:
6867 case Xsand_stonein_1:
6868 case Xsand_stonein_2:
6869 case Xsand_stonein_3:
6870 case Xsand_stonein_4:
6874 return (is_backside || action_removing ? EL_EMPTY : element);
6879 inline static boolean check_linear_animation_EM(int tile)
6883 case Xsand_stonesand_1:
6884 case Xsand_stonesand_quickout_1:
6885 case Xsand_sandstone_1:
6886 case Xsand_stonein_1:
6887 case Xsand_stoneout_1:
6906 case Yacid_splash_eB:
6907 case Yacid_splash_wB:
6908 case Yemerald_stone:
6915 inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
6916 boolean has_crumbled_graphics,
6917 int crumbled, int sync_frame)
6919 /* if element can be crumbled, but certain action graphics are just empty
6920 space (like instantly snapping sand to empty space in 1 frame), do not
6921 treat these empty space graphics as crumbled graphics in EMC engine */
6922 if (crumbled == IMG_EMPTY_SPACE)
6923 has_crumbled_graphics = FALSE;
6925 if (has_crumbled_graphics)
6927 struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
6928 int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
6929 g_crumbled->anim_delay,
6930 g_crumbled->anim_mode,
6931 g_crumbled->anim_start_frame,
6934 getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
6935 &g_em->crumbled_src_x, &g_em->crumbled_src_y);
6937 g_em->crumbled_border_size = graphic_info[crumbled].border_size;
6939 g_em->has_crumbled_graphics = TRUE;
6943 g_em->crumbled_bitmap = NULL;
6944 g_em->crumbled_src_x = 0;
6945 g_em->crumbled_src_y = 0;
6946 g_em->crumbled_border_size = 0;
6948 g_em->has_crumbled_graphics = FALSE;
6952 void ResetGfxAnimation_EM(int x, int y, int tile)
6957 void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
6958 int tile, int frame_em, int x, int y)
6960 int action = object_mapping[tile].action;
6961 int direction = object_mapping[tile].direction;
6962 int effective_element = get_effective_element_EM(tile, frame_em);
6963 int graphic = (direction == MV_NONE ?
6964 el_act2img(effective_element, action) :
6965 el_act_dir2img(effective_element, action, direction));
6966 struct GraphicInfo *g = &graphic_info[graphic];
6968 boolean action_removing = (action == ACTION_DIGGING ||
6969 action == ACTION_SNAPPING ||
6970 action == ACTION_COLLECTING);
6971 boolean action_moving = (action == ACTION_FALLING ||
6972 action == ACTION_MOVING ||
6973 action == ACTION_PUSHING ||
6974 action == ACTION_EATING ||
6975 action == ACTION_FILLING ||
6976 action == ACTION_EMPTYING);
6977 boolean action_falling = (action == ACTION_FALLING ||
6978 action == ACTION_FILLING ||
6979 action == ACTION_EMPTYING);
6981 /* special case: graphic uses "2nd movement tile" and has defined
6982 7 frames for movement animation (or less) => use default graphic
6983 for last (8th) frame which ends the movement animation */
6984 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
6986 action = ACTION_DEFAULT; /* (keep action_* unchanged for now) */
6987 graphic = (direction == MV_NONE ?
6988 el_act2img(effective_element, action) :
6989 el_act_dir2img(effective_element, action, direction));
6991 g = &graphic_info[graphic];
6994 if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
6998 else if (action_moving)
7000 boolean is_backside = object_mapping[tile].is_backside;
7004 int direction = object_mapping[tile].direction;
7005 int move_dir = (action_falling ? MV_DOWN : direction);
7010 /* !!! TEST !!! NEW !!! DOES NOT WORK RIGHT YET !!! */
7011 if (g->double_movement && frame_em == 0)
7015 if (move_dir == MV_LEFT)
7016 GfxFrame[x - 1][y] = GfxFrame[x][y];
7017 else if (move_dir == MV_RIGHT)
7018 GfxFrame[x + 1][y] = GfxFrame[x][y];
7019 else if (move_dir == MV_UP)
7020 GfxFrame[x][y - 1] = GfxFrame[x][y];
7021 else if (move_dir == MV_DOWN)
7022 GfxFrame[x][y + 1] = GfxFrame[x][y];
7029 /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
7030 if (tile == Xsand_stonesand_quickout_1 ||
7031 tile == Xsand_stonesand_quickout_2)
7035 if (graphic_info[graphic].anim_global_sync)
7036 sync_frame = FrameCounter;
7037 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7038 sync_frame = GfxFrame[x][y];
7040 sync_frame = 0; /* playfield border (pseudo steel) */
7042 SetRandomAnimationValue(x, y);
7044 int frame = getAnimationFrame(g->anim_frames,
7047 g->anim_start_frame,
7050 g_em->unique_identifier =
7051 (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
7054 void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
7055 int tile, int frame_em, int x, int y)
7057 int action = object_mapping[tile].action;
7058 int direction = object_mapping[tile].direction;
7059 boolean is_backside = object_mapping[tile].is_backside;
7060 int effective_element = get_effective_element_EM(tile, frame_em);
7061 int effective_action = action;
7062 int graphic = (direction == MV_NONE ?
7063 el_act2img(effective_element, effective_action) :
7064 el_act_dir2img(effective_element, effective_action,
7066 int crumbled = (direction == MV_NONE ?
7067 el_act2crm(effective_element, effective_action) :
7068 el_act_dir2crm(effective_element, effective_action,
7070 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7071 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7072 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7073 struct GraphicInfo *g = &graphic_info[graphic];
7076 /* special case: graphic uses "2nd movement tile" and has defined
7077 7 frames for movement animation (or less) => use default graphic
7078 for last (8th) frame which ends the movement animation */
7079 if (g->double_movement && g->anim_frames < 8 && frame_em == 7)
7081 effective_action = ACTION_DEFAULT;
7082 graphic = (direction == MV_NONE ?
7083 el_act2img(effective_element, effective_action) :
7084 el_act_dir2img(effective_element, effective_action,
7086 crumbled = (direction == MV_NONE ?
7087 el_act2crm(effective_element, effective_action) :
7088 el_act_dir2crm(effective_element, effective_action,
7091 g = &graphic_info[graphic];
7094 if (graphic_info[graphic].anim_global_sync)
7095 sync_frame = FrameCounter;
7096 else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
7097 sync_frame = GfxFrame[x][y];
7099 sync_frame = 0; /* playfield border (pseudo steel) */
7101 SetRandomAnimationValue(x, y);
7103 int frame = getAnimationFrame(g->anim_frames,
7106 g->anim_start_frame,
7109 getGraphicSourceExt(graphic, frame, &g_em->bitmap, &g_em->src_x, &g_em->src_y,
7110 g->double_movement && is_backside);
7112 /* (updating the "crumbled" graphic definitions is probably not really needed,
7113 as animations for crumbled graphics can't be longer than one EMC cycle) */
7114 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7118 void getGraphicSourcePlayerExt_EM(struct GraphicInfo_EM *g_em,
7119 int player_nr, int anim, int frame_em)
7121 int element = player_mapping[player_nr][anim].element_rnd;
7122 int action = player_mapping[player_nr][anim].action;
7123 int direction = player_mapping[player_nr][anim].direction;
7124 int graphic = (direction == MV_NONE ?
7125 el_act2img(element, action) :
7126 el_act_dir2img(element, action, direction));
7127 struct GraphicInfo *g = &graphic_info[graphic];
7130 InitPlayerGfxAnimation(&stored_player[player_nr], action, direction);
7132 stored_player[player_nr].StepFrame = frame_em;
7134 sync_frame = stored_player[player_nr].Frame;
7136 int frame = getAnimationFrame(g->anim_frames,
7139 g->anim_start_frame,
7142 getGraphicSourceExt(graphic, frame, &g_em->bitmap,
7143 &g_em->src_x, &g_em->src_y, FALSE);
7146 void InitGraphicInfo_EM(void)
7151 int num_em_gfx_errors = 0;
7153 if (graphic_info_em_object[0][0].bitmap == NULL)
7155 /* EM graphics not yet initialized in em_open_all() */
7160 printf("::: [4 errors can be ignored (1 x 'bomb', 3 x 'em_dynamite']\n");
7163 /* always start with reliable default values */
7164 for (i = 0; i < TILE_MAX; i++)
7166 object_mapping[i].element_rnd = EL_UNKNOWN;
7167 object_mapping[i].is_backside = FALSE;
7168 object_mapping[i].action = ACTION_DEFAULT;
7169 object_mapping[i].direction = MV_NONE;
7172 /* always start with reliable default values */
7173 for (p = 0; p < MAX_PLAYERS; p++)
7175 for (i = 0; i < SPR_MAX; i++)
7177 player_mapping[p][i].element_rnd = EL_UNKNOWN;
7178 player_mapping[p][i].action = ACTION_DEFAULT;
7179 player_mapping[p][i].direction = MV_NONE;
7183 for (i = 0; em_object_mapping_list[i].element_em != -1; i++)
7185 int e = em_object_mapping_list[i].element_em;
7187 object_mapping[e].element_rnd = em_object_mapping_list[i].element_rnd;
7188 object_mapping[e].is_backside = em_object_mapping_list[i].is_backside;
7190 if (em_object_mapping_list[i].action != -1)
7191 object_mapping[e].action = em_object_mapping_list[i].action;
7193 if (em_object_mapping_list[i].direction != -1)
7194 object_mapping[e].direction =
7195 MV_DIR_FROM_BIT(em_object_mapping_list[i].direction);
7198 for (i = 0; em_player_mapping_list[i].action_em != -1; i++)
7200 int a = em_player_mapping_list[i].action_em;
7201 int p = em_player_mapping_list[i].player_nr;
7203 player_mapping[p][a].element_rnd = em_player_mapping_list[i].element_rnd;
7205 if (em_player_mapping_list[i].action != -1)
7206 player_mapping[p][a].action = em_player_mapping_list[i].action;
7208 if (em_player_mapping_list[i].direction != -1)
7209 player_mapping[p][a].direction =
7210 MV_DIR_FROM_BIT(em_player_mapping_list[i].direction);
7213 for (i = 0; i < TILE_MAX; i++)
7215 int element = object_mapping[i].element_rnd;
7216 int action = object_mapping[i].action;
7217 int direction = object_mapping[i].direction;
7218 boolean is_backside = object_mapping[i].is_backside;
7219 boolean action_exploding = ((action == ACTION_EXPLODING ||
7220 action == ACTION_SMASHED_BY_ROCK ||
7221 action == ACTION_SMASHED_BY_SPRING) &&
7222 element != EL_DIAMOND);
7223 boolean action_active = (action == ACTION_ACTIVE);
7224 boolean action_other = (action == ACTION_OTHER);
7226 for (j = 0; j < 8; j++)
7228 int effective_element = get_effective_element_EM(i, j);
7229 int effective_action = (j < 7 ? action :
7230 i == Xdrip_stretch ? action :
7231 i == Xdrip_stretchB ? action :
7232 i == Ydrip_s1 ? action :
7233 i == Ydrip_s1B ? action :
7234 i == Xball_1B ? action :
7235 i == Xball_2 ? action :
7236 i == Xball_2B ? action :
7237 i == Yball_eat ? action :
7238 i == Ykey_1_eat ? action :
7239 i == Ykey_2_eat ? action :
7240 i == Ykey_3_eat ? action :
7241 i == Ykey_4_eat ? action :
7242 i == Ykey_5_eat ? action :
7243 i == Ykey_6_eat ? action :
7244 i == Ykey_7_eat ? action :
7245 i == Ykey_8_eat ? action :
7246 i == Ylenses_eat ? action :
7247 i == Ymagnify_eat ? action :
7248 i == Ygrass_eat ? action :
7249 i == Ydirt_eat ? action :
7250 i == Xsand_stonein_1 ? action :
7251 i == Xsand_stonein_2 ? action :
7252 i == Xsand_stonein_3 ? action :
7253 i == Xsand_stonein_4 ? action :
7254 i == Xsand_stoneout_1 ? action :
7255 i == Xsand_stoneout_2 ? action :
7256 i == Xboom_android ? ACTION_EXPLODING :
7257 action_exploding ? ACTION_EXPLODING :
7258 action_active ? action :
7259 action_other ? action :
7261 int graphic = (el_act_dir2img(effective_element, effective_action,
7263 int crumbled = (el_act_dir2crm(effective_element, effective_action,
7265 int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
7266 int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
7267 boolean has_action_graphics = (graphic != base_graphic);
7268 boolean has_crumbled_graphics = (base_crumbled != base_graphic);
7269 struct GraphicInfo *g = &graphic_info[graphic];
7270 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7273 /* ensure to get symmetric 3-frame, 2-delay animations as used in EM */
7274 boolean special_animation = (action != ACTION_DEFAULT &&
7275 g->anim_frames == 3 &&
7276 g->anim_delay == 2 &&
7277 g->anim_mode & ANIM_LINEAR);
7278 int sync_frame = (i == Xdrip_stretch ? 7 :
7279 i == Xdrip_stretchB ? 7 :
7280 i == Ydrip_s2 ? j + 8 :
7281 i == Ydrip_s2B ? j + 8 :
7290 i == Xfake_acid_1 ? 0 :
7291 i == Xfake_acid_2 ? 10 :
7292 i == Xfake_acid_3 ? 20 :
7293 i == Xfake_acid_4 ? 30 :
7294 i == Xfake_acid_5 ? 40 :
7295 i == Xfake_acid_6 ? 50 :
7296 i == Xfake_acid_7 ? 60 :
7297 i == Xfake_acid_8 ? 70 :
7299 i == Xball_2B ? j + 8 :
7300 i == Yball_eat ? j + 1 :
7301 i == Ykey_1_eat ? j + 1 :
7302 i == Ykey_2_eat ? j + 1 :
7303 i == Ykey_3_eat ? j + 1 :
7304 i == Ykey_4_eat ? j + 1 :
7305 i == Ykey_5_eat ? j + 1 :
7306 i == Ykey_6_eat ? j + 1 :
7307 i == Ykey_7_eat ? j + 1 :
7308 i == Ykey_8_eat ? j + 1 :
7309 i == Ylenses_eat ? j + 1 :
7310 i == Ymagnify_eat ? j + 1 :
7311 i == Ygrass_eat ? j + 1 :
7312 i == Ydirt_eat ? j + 1 :
7313 i == Xamoeba_1 ? 0 :
7314 i == Xamoeba_2 ? 1 :
7315 i == Xamoeba_3 ? 2 :
7316 i == Xamoeba_4 ? 3 :
7317 i == Xamoeba_5 ? 0 :
7318 i == Xamoeba_6 ? 1 :
7319 i == Xamoeba_7 ? 2 :
7320 i == Xamoeba_8 ? 3 :
7321 i == Xexit_2 ? j + 8 :
7322 i == Xexit_3 ? j + 16 :
7323 i == Xdynamite_1 ? 0 :
7324 i == Xdynamite_2 ? 8 :
7325 i == Xdynamite_3 ? 16 :
7326 i == Xdynamite_4 ? 24 :
7327 i == Xsand_stonein_1 ? j + 1 :
7328 i == Xsand_stonein_2 ? j + 9 :
7329 i == Xsand_stonein_3 ? j + 17 :
7330 i == Xsand_stonein_4 ? j + 25 :
7331 i == Xsand_stoneout_1 && j == 0 ? 0 :
7332 i == Xsand_stoneout_1 && j == 1 ? 0 :
7333 i == Xsand_stoneout_1 && j == 2 ? 1 :
7334 i == Xsand_stoneout_1 && j == 3 ? 2 :
7335 i == Xsand_stoneout_1 && j == 4 ? 2 :
7336 i == Xsand_stoneout_1 && j == 5 ? 3 :
7337 i == Xsand_stoneout_1 && j == 6 ? 4 :
7338 i == Xsand_stoneout_1 && j == 7 ? 4 :
7339 i == Xsand_stoneout_2 && j == 0 ? 5 :
7340 i == Xsand_stoneout_2 && j == 1 ? 6 :
7341 i == Xsand_stoneout_2 && j == 2 ? 7 :
7342 i == Xsand_stoneout_2 && j == 3 ? 8 :
7343 i == Xsand_stoneout_2 && j == 4 ? 9 :
7344 i == Xsand_stoneout_2 && j == 5 ? 11 :
7345 i == Xsand_stoneout_2 && j == 6 ? 13 :
7346 i == Xsand_stoneout_2 && j == 7 ? 15 :
7347 i == Xboom_bug && j == 1 ? 2 :
7348 i == Xboom_bug && j == 2 ? 2 :
7349 i == Xboom_bug && j == 3 ? 4 :
7350 i == Xboom_bug && j == 4 ? 4 :
7351 i == Xboom_bug && j == 5 ? 2 :
7352 i == Xboom_bug && j == 6 ? 2 :
7353 i == Xboom_bug && j == 7 ? 0 :
7354 i == Xboom_bomb && j == 1 ? 2 :
7355 i == Xboom_bomb && j == 2 ? 2 :
7356 i == Xboom_bomb && j == 3 ? 4 :
7357 i == Xboom_bomb && j == 4 ? 4 :
7358 i == Xboom_bomb && j == 5 ? 2 :
7359 i == Xboom_bomb && j == 6 ? 2 :
7360 i == Xboom_bomb && j == 7 ? 0 :
7361 i == Xboom_android && j == 7 ? 6 :
7362 i == Xboom_1 && j == 1 ? 2 :
7363 i == Xboom_1 && j == 2 ? 2 :
7364 i == Xboom_1 && j == 3 ? 4 :
7365 i == Xboom_1 && j == 4 ? 4 :
7366 i == Xboom_1 && j == 5 ? 6 :
7367 i == Xboom_1 && j == 6 ? 6 :
7368 i == Xboom_1 && j == 7 ? 8 :
7369 i == Xboom_2 && j == 0 ? 8 :
7370 i == Xboom_2 && j == 1 ? 8 :
7371 i == Xboom_2 && j == 2 ? 10 :
7372 i == Xboom_2 && j == 3 ? 10 :
7373 i == Xboom_2 && j == 4 ? 10 :
7374 i == Xboom_2 && j == 5 ? 12 :
7375 i == Xboom_2 && j == 6 ? 12 :
7376 i == Xboom_2 && j == 7 ? 12 :
7377 special_animation && j == 4 ? 3 :
7378 effective_action != action ? 0 :
7382 Bitmap *debug_bitmap = g_em->bitmap;
7383 int debug_src_x = g_em->src_x;
7384 int debug_src_y = g_em->src_y;
7387 int frame = getAnimationFrame(g->anim_frames,
7390 g->anim_start_frame,
7393 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y,
7394 g->double_movement && is_backside);
7396 g_em->bitmap = src_bitmap;
7397 g_em->src_x = src_x;
7398 g_em->src_y = src_y;
7399 g_em->src_offset_x = 0;
7400 g_em->src_offset_y = 0;
7401 g_em->dst_offset_x = 0;
7402 g_em->dst_offset_y = 0;
7403 g_em->width = TILEX;
7404 g_em->height = TILEY;
7406 g_em->preserve_background = FALSE;
7408 set_crumbled_graphics_EM(g_em, has_crumbled_graphics, crumbled,
7411 if ((!g->double_movement && (effective_action == ACTION_FALLING ||
7412 effective_action == ACTION_MOVING ||
7413 effective_action == ACTION_PUSHING ||
7414 effective_action == ACTION_EATING)) ||
7415 (!has_action_graphics && (effective_action == ACTION_FILLING ||
7416 effective_action == ACTION_EMPTYING)))
7419 (effective_action == ACTION_FALLING ||
7420 effective_action == ACTION_FILLING ||
7421 effective_action == ACTION_EMPTYING ? MV_DOWN : direction);
7422 int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? 1 : 0);
7423 int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? 1 : 0);
7424 int num_steps = (i == Ydrip_s1 ? 16 :
7425 i == Ydrip_s1B ? 16 :
7426 i == Ydrip_s2 ? 16 :
7427 i == Ydrip_s2B ? 16 :
7428 i == Xsand_stonein_1 ? 32 :
7429 i == Xsand_stonein_2 ? 32 :
7430 i == Xsand_stonein_3 ? 32 :
7431 i == Xsand_stonein_4 ? 32 :
7432 i == Xsand_stoneout_1 ? 16 :
7433 i == Xsand_stoneout_2 ? 16 : 8);
7434 int cx = ABS(dx) * (TILEX / num_steps);
7435 int cy = ABS(dy) * (TILEY / num_steps);
7436 int step_frame = (i == Ydrip_s2 ? j + 8 :
7437 i == Ydrip_s2B ? j + 8 :
7438 i == Xsand_stonein_2 ? j + 8 :
7439 i == Xsand_stonein_3 ? j + 16 :
7440 i == Xsand_stonein_4 ? j + 24 :
7441 i == Xsand_stoneout_2 ? j + 8 : j) + 1;
7442 int step = (is_backside ? step_frame : num_steps - step_frame);
7444 if (is_backside) /* tile where movement starts */
7446 if (dx < 0 || dy < 0)
7448 g_em->src_offset_x = cx * step;
7449 g_em->src_offset_y = cy * step;
7453 g_em->dst_offset_x = cx * step;
7454 g_em->dst_offset_y = cy * step;
7457 else /* tile where movement ends */
7459 if (dx < 0 || dy < 0)
7461 g_em->dst_offset_x = cx * step;
7462 g_em->dst_offset_y = cy * step;
7466 g_em->src_offset_x = cx * step;
7467 g_em->src_offset_y = cy * step;
7471 g_em->width = TILEX - cx * step;
7472 g_em->height = TILEY - cy * step;
7475 /* create unique graphic identifier to decide if tile must be redrawn */
7476 /* bit 31 - 16 (16 bit): EM style graphic
7477 bit 15 - 12 ( 4 bit): EM style frame
7478 bit 11 - 6 ( 6 bit): graphic width
7479 bit 5 - 0 ( 6 bit): graphic height */
7480 g_em->unique_identifier =
7481 (graphic << 16) | (frame << 12) | (g_em->width << 6) | g_em->height;
7485 /* skip check for EMC elements not contained in original EMC artwork */
7486 if (element == EL_EMC_FAKE_ACID)
7489 if (g_em->bitmap != debug_bitmap ||
7490 g_em->src_x != debug_src_x ||
7491 g_em->src_y != debug_src_y ||
7492 g_em->src_offset_x != 0 ||
7493 g_em->src_offset_y != 0 ||
7494 g_em->dst_offset_x != 0 ||
7495 g_em->dst_offset_y != 0 ||
7496 g_em->width != TILEX ||
7497 g_em->height != TILEY)
7499 static int last_i = -1;
7507 printf("::: EMC GFX ERROR for element %d -> %d ('%s', '%s', %d)",
7508 i, element, element_info[element].token_name,
7509 element_action_info[effective_action].suffix, direction);
7511 if (element != effective_element)
7512 printf(" [%d ('%s')]",
7514 element_info[effective_element].token_name);
7518 if (g_em->bitmap != debug_bitmap)
7519 printf(" %d (%d): different bitmap! (0x%08x != 0x%08x)\n",
7520 j, is_backside, (int)(g_em->bitmap), (int)(debug_bitmap));
7522 if (g_em->src_x != debug_src_x ||
7523 g_em->src_y != debug_src_y)
7524 printf(" frame %d (%c): %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7525 j, (is_backside ? 'B' : 'F'),
7526 g_em->src_x, g_em->src_y,
7527 g_em->src_x / 32, g_em->src_y / 32,
7528 debug_src_x, debug_src_y,
7529 debug_src_x / 32, debug_src_y / 32);
7531 if (g_em->src_offset_x != 0 ||
7532 g_em->src_offset_y != 0 ||
7533 g_em->dst_offset_x != 0 ||
7534 g_em->dst_offset_y != 0)
7535 printf(" %d (%d): offsets %d,%d and %d,%d should be all 0\n",
7537 g_em->src_offset_x, g_em->src_offset_y,
7538 g_em->dst_offset_x, g_em->dst_offset_y);
7540 if (g_em->width != TILEX ||
7541 g_em->height != TILEY)
7542 printf(" %d (%d): size %d,%d should be %d,%d\n",
7544 g_em->width, g_em->height, TILEX, TILEY);
7546 num_em_gfx_errors++;
7553 for (i = 0; i < TILE_MAX; i++)
7555 for (j = 0; j < 8; j++)
7557 int element = object_mapping[i].element_rnd;
7558 int action = object_mapping[i].action;
7559 int direction = object_mapping[i].direction;
7560 boolean is_backside = object_mapping[i].is_backside;
7561 int graphic_action = el_act_dir2img(element, action, direction);
7562 int graphic_default = el_act_dir2img(element, ACTION_DEFAULT, direction);
7564 if ((action == ACTION_SMASHED_BY_ROCK ||
7565 action == ACTION_SMASHED_BY_SPRING ||
7566 action == ACTION_EATING) &&
7567 graphic_action == graphic_default)
7569 int e = (action == ACTION_SMASHED_BY_ROCK ? Ystone_s :
7570 action == ACTION_SMASHED_BY_SPRING ? Yspring_s :
7571 direction == MV_LEFT ? (is_backside? Yspring_wB: Yspring_w) :
7572 direction == MV_RIGHT ? (is_backside? Yspring_eB: Yspring_e) :
7575 /* no separate animation for "smashed by rock" -- use rock instead */
7576 struct GraphicInfo_EM *g_em = &graphic_info_em_object[i][7 - j];
7577 struct GraphicInfo_EM *g_xx = &graphic_info_em_object[e][7 - j];
7579 g_em->bitmap = g_xx->bitmap;
7580 g_em->src_x = g_xx->src_x;
7581 g_em->src_y = g_xx->src_y;
7582 g_em->src_offset_x = g_xx->src_offset_x;
7583 g_em->src_offset_y = g_xx->src_offset_y;
7584 g_em->dst_offset_x = g_xx->dst_offset_x;
7585 g_em->dst_offset_y = g_xx->dst_offset_y;
7586 g_em->width = g_xx->width;
7587 g_em->height = g_xx->height;
7588 g_em->unique_identifier = g_xx->unique_identifier;
7591 g_em->preserve_background = TRUE;
7596 for (p = 0; p < MAX_PLAYERS; p++)
7598 for (i = 0; i < SPR_MAX; i++)
7600 int element = player_mapping[p][i].element_rnd;
7601 int action = player_mapping[p][i].action;
7602 int direction = player_mapping[p][i].direction;
7604 for (j = 0; j < 8; j++)
7606 int effective_element = element;
7607 int effective_action = action;
7608 int graphic = (direction == MV_NONE ?
7609 el_act2img(effective_element, effective_action) :
7610 el_act_dir2img(effective_element, effective_action,
7612 struct GraphicInfo *g = &graphic_info[graphic];
7613 struct GraphicInfo_EM *g_em = &graphic_info_em_player[p][i][7 - j];
7619 Bitmap *debug_bitmap = g_em->bitmap;
7620 int debug_src_x = g_em->src_x;
7621 int debug_src_y = g_em->src_y;
7624 int frame = getAnimationFrame(g->anim_frames,
7627 g->anim_start_frame,
7630 getGraphicSourceExt(graphic, frame, &src_bitmap, &src_x, &src_y, FALSE);
7632 g_em->bitmap = src_bitmap;
7633 g_em->src_x = src_x;
7634 g_em->src_y = src_y;
7635 g_em->src_offset_x = 0;
7636 g_em->src_offset_y = 0;
7637 g_em->dst_offset_x = 0;
7638 g_em->dst_offset_y = 0;
7639 g_em->width = TILEX;
7640 g_em->height = TILEY;
7644 /* skip check for EMC elements not contained in original EMC artwork */
7645 if (element == EL_PLAYER_3 ||
7646 element == EL_PLAYER_4)
7649 if (g_em->bitmap != debug_bitmap ||
7650 g_em->src_x != debug_src_x ||
7651 g_em->src_y != debug_src_y)
7653 static int last_i = -1;
7661 printf("::: EMC GFX ERROR for p/a %d/%d -> %d ('%s', '%s', %d)",
7662 p, i, element, element_info[element].token_name,
7663 element_action_info[effective_action].suffix, direction);
7665 if (element != effective_element)
7666 printf(" [%d ('%s')]",
7668 element_info[effective_element].token_name);
7672 if (g_em->bitmap != debug_bitmap)
7673 printf(" %d: different bitmap! (0x%08x != 0x%08x)\n",
7674 j, (int)(g_em->bitmap), (int)(debug_bitmap));
7676 if (g_em->src_x != debug_src_x ||
7677 g_em->src_y != debug_src_y)
7678 printf(" frame %d: %d,%d (%d,%d) should be %d,%d (%d,%d)\n",
7680 g_em->src_x, g_em->src_y,
7681 g_em->src_x / 32, g_em->src_y / 32,
7682 debug_src_x, debug_src_y,
7683 debug_src_x / 32, debug_src_y / 32);
7685 num_em_gfx_errors++;
7695 printf("::: [%d errors found]\n", num_em_gfx_errors);
7701 void CheckSaveEngineSnapshot_EM(byte action[MAX_PLAYERS], int frame,
7702 boolean any_player_moving,
7703 boolean any_player_snapping,
7704 boolean any_player_dropping)
7706 static boolean player_was_waiting = TRUE;
7708 if (frame == 0 && !any_player_dropping)
7710 if (!player_was_waiting)
7712 if (!SaveEngineSnapshotToList())
7715 player_was_waiting = TRUE;
7718 else if (any_player_moving || any_player_snapping || any_player_dropping)
7720 player_was_waiting = FALSE;
7724 void CheckSaveEngineSnapshot_SP(boolean murphy_is_waiting,
7725 boolean murphy_is_dropping)
7727 static boolean player_was_waiting = TRUE;
7729 if (murphy_is_waiting)
7731 if (!player_was_waiting)
7733 if (!SaveEngineSnapshotToList())
7736 player_was_waiting = TRUE;
7741 player_was_waiting = FALSE;
7745 void CheckSingleStepMode_EM(byte action[MAX_PLAYERS], int frame,
7746 boolean any_player_moving,
7747 boolean any_player_snapping,
7748 boolean any_player_dropping)
7750 if (tape.single_step && tape.recording && !tape.pausing)
7751 if (frame == 0 && !any_player_dropping)
7752 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7754 CheckSaveEngineSnapshot_EM(action, frame, any_player_moving,
7755 any_player_snapping, any_player_dropping);
7758 void CheckSingleStepMode_SP(boolean murphy_is_waiting,
7759 boolean murphy_is_dropping)
7761 if (tape.single_step && tape.recording && !tape.pausing)
7762 if (murphy_is_waiting)
7763 TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
7765 CheckSaveEngineSnapshot_SP(murphy_is_waiting, murphy_is_dropping);
7768 void getGraphicSource_SP(struct GraphicInfo_SP *g_sp,
7769 int graphic, int sync_frame, int x, int y)
7771 int frame = getGraphicAnimationFrame(graphic, sync_frame);
7773 getGraphicSource(graphic, frame, &g_sp->bitmap, &g_sp->src_x, &g_sp->src_y);
7776 boolean isNextAnimationFrame_SP(int graphic, int sync_frame)
7778 return (IS_NEXT_FRAME(sync_frame, graphic));
7781 int getGraphicInfo_Delay(int graphic)
7783 return graphic_info[graphic].anim_delay;
7786 void PlayMenuSoundExt(int sound)
7788 if (sound == SND_UNDEFINED)
7791 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7792 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7795 if (IS_LOOP_SOUND(sound))
7796 PlaySoundLoop(sound);
7801 void PlayMenuSound()
7803 PlayMenuSoundExt(menu.sound[game_status]);
7806 void PlayMenuSoundStereo(int sound, int stereo_position)
7808 if (sound == SND_UNDEFINED)
7811 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7812 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7815 if (IS_LOOP_SOUND(sound))
7816 PlaySoundExt(sound, SOUND_MAX_VOLUME, stereo_position, SND_CTRL_PLAY_LOOP);
7818 PlaySoundStereo(sound, stereo_position);
7821 void PlayMenuSoundIfLoopExt(int sound)
7823 if (sound == SND_UNDEFINED)
7826 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound)) ||
7827 (!setup.sound_loops && IS_LOOP_SOUND(sound)))
7830 if (IS_LOOP_SOUND(sound))
7831 PlaySoundLoop(sound);
7834 void PlayMenuSoundIfLoop()
7836 PlayMenuSoundIfLoopExt(menu.sound[game_status]);
7839 void PlayMenuMusicExt(int music)
7841 if (music == MUS_UNDEFINED)
7844 if (!setup.sound_music)
7850 void PlayMenuMusic()
7852 PlayMenuMusicExt(menu.music[game_status]);
7855 void PlaySoundActivating()
7858 PlaySound(SND_MENU_ITEM_ACTIVATING);
7862 void PlaySoundSelecting()
7865 PlaySound(SND_MENU_ITEM_SELECTING);
7869 void ToggleFullscreenOrChangeWindowScalingIfNeeded()
7871 boolean change_fullscreen = (setup.fullscreen !=
7872 video.fullscreen_enabled);
7873 boolean change_fullscreen_mode = (video.fullscreen_enabled &&
7874 !strEqual(setup.fullscreen_mode,
7875 video.fullscreen_mode_current));
7876 boolean change_window_scaling_percent = (!video.fullscreen_enabled &&
7877 setup.window_scaling_percent !=
7878 video.window_scaling_percent);
7880 if (change_window_scaling_percent && video.fullscreen_enabled)
7883 if (!change_window_scaling_percent && !video.fullscreen_available)
7886 #if defined(TARGET_SDL2)
7887 if (change_window_scaling_percent)
7889 SDLSetWindowScaling(setup.window_scaling_percent);
7893 else if (change_fullscreen)
7895 SDLSetWindowFullscreen(setup.fullscreen);
7897 /* set setup value according to successfully changed fullscreen mode */
7898 setup.fullscreen = video.fullscreen_enabled;
7904 if (change_fullscreen ||
7905 change_fullscreen_mode ||
7906 change_window_scaling_percent)
7908 Bitmap *tmp_backbuffer = CreateBitmap(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH);
7910 /* save backbuffer content which gets lost when toggling fullscreen mode */
7911 BlitBitmap(backbuffer, tmp_backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7913 if (change_fullscreen_mode)
7915 /* keep fullscreen, but change fullscreen mode (screen resolution) */
7916 video.fullscreen_enabled = FALSE; /* force new fullscreen mode */
7919 if (change_window_scaling_percent)
7921 /* keep window mode, but change window scaling */
7922 video.fullscreen_enabled = TRUE; /* force new window scaling */
7925 /* toggle fullscreen */
7926 ChangeVideoModeIfNeeded(setup.fullscreen);
7928 /* set setup value according to successfully changed fullscreen mode */
7929 setup.fullscreen = video.fullscreen_enabled;
7931 /* restore backbuffer content from temporary backbuffer backup bitmap */
7932 BlitBitmap(tmp_backbuffer, backbuffer, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7934 FreeBitmap(tmp_backbuffer);
7936 /* update visible window/screen */
7937 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
7941 void ChangeViewportPropertiesIfNeeded()
7943 int gfx_game_mode = game_status;
7944 int gfx_game_mode2 = (game_status == GAME_MODE_EDITOR ? GAME_MODE_DEFAULT :
7946 struct RectWithBorder *vp_playfield = &viewport.playfield[gfx_game_mode];
7947 struct RectWithBorder *vp_door_1 = &viewport.door_1[gfx_game_mode];
7948 struct RectWithBorder *vp_door_2 = &viewport.door_2[gfx_game_mode2];
7949 struct RectWithBorder *vp_door_3 = &viewport.door_2[GAME_MODE_EDITOR];
7950 int border_size = vp_playfield->border_size;
7951 int new_sx = vp_playfield->x + border_size;
7952 int new_sy = vp_playfield->y + border_size;
7953 int new_sxsize = vp_playfield->width - 2 * border_size;
7954 int new_sysize = vp_playfield->height - 2 * border_size;
7955 int new_real_sx = vp_playfield->x;
7956 int new_real_sy = vp_playfield->y;
7957 int new_full_sxsize = vp_playfield->width;
7958 int new_full_sysize = vp_playfield->height;
7959 int new_dx = vp_door_1->x;
7960 int new_dy = vp_door_1->y;
7961 int new_dxsize = vp_door_1->width;
7962 int new_dysize = vp_door_1->height;
7963 int new_vx = vp_door_2->x;
7964 int new_vy = vp_door_2->y;
7965 int new_vxsize = vp_door_2->width;
7966 int new_vysize = vp_door_2->height;
7967 int new_ex = vp_door_3->x;
7968 int new_ey = vp_door_3->y;
7969 int new_exsize = vp_door_3->width;
7970 int new_eysize = vp_door_3->height;
7971 int new_tilesize_var =
7972 (setup.small_game_graphics ? MINI_TILESIZE : game.tile_size);
7974 int tilesize = (gfx_game_mode == GAME_MODE_PLAYING ? new_tilesize_var :
7975 gfx_game_mode == GAME_MODE_EDITOR ? MINI_TILESIZE : TILESIZE);
7976 int new_scr_fieldx = new_sxsize / tilesize;
7977 int new_scr_fieldy = new_sysize / tilesize;
7978 int new_scr_fieldx_buffers = new_sxsize / new_tilesize_var;
7979 int new_scr_fieldy_buffers = new_sysize / new_tilesize_var;
7980 boolean init_gfx_buffers = FALSE;
7981 boolean init_video_buffer = FALSE;
7982 boolean init_gadgets_and_toons = FALSE;
7983 boolean init_em_graphics = FALSE;
7984 boolean drawing_area_changed = FALSE;
7986 if (viewport.window.width != WIN_XSIZE ||
7987 viewport.window.height != WIN_YSIZE)
7989 WIN_XSIZE = viewport.window.width;
7990 WIN_YSIZE = viewport.window.height;
7992 init_video_buffer = TRUE;
7993 init_gfx_buffers = TRUE;
7995 // printf("::: video: init_video_buffer, init_gfx_buffers\n");
7998 if (new_scr_fieldx != SCR_FIELDX ||
7999 new_scr_fieldy != SCR_FIELDY)
8001 /* this always toggles between MAIN and GAME when using small tile size */
8003 SCR_FIELDX = new_scr_fieldx;
8004 SCR_FIELDY = new_scr_fieldy;
8006 // printf("::: new_scr_fieldx != SCR_FIELDX ...\n");
8017 new_sxsize != SXSIZE ||
8018 new_sysize != SYSIZE ||
8019 new_dxsize != DXSIZE ||
8020 new_dysize != DYSIZE ||
8021 new_vxsize != VXSIZE ||
8022 new_vysize != VYSIZE ||
8023 new_exsize != EXSIZE ||
8024 new_eysize != EYSIZE ||
8025 new_real_sx != REAL_SX ||
8026 new_real_sy != REAL_SY ||
8027 new_full_sxsize != FULL_SXSIZE ||
8028 new_full_sysize != FULL_SYSIZE ||
8029 new_tilesize_var != TILESIZE_VAR
8032 if (new_tilesize_var != TILESIZE_VAR)
8034 // printf("::: new_tilesize_var != TILESIZE_VAR\n");
8036 // changing tile size invalidates scroll values of engine snapshots
8037 FreeEngineSnapshotSingle();
8039 // changing tile size requires update of graphic mapping for EM engine
8040 init_em_graphics = TRUE;
8045 new_sxsize != SXSIZE ||
8046 new_sysize != SYSIZE ||
8047 new_real_sx != REAL_SX ||
8048 new_real_sy != REAL_SY ||
8049 new_full_sxsize != FULL_SXSIZE ||
8050 new_full_sysize != FULL_SYSIZE)
8052 if (!init_video_buffer)
8053 drawing_area_changed = TRUE;
8064 SXSIZE = new_sxsize;
8065 SYSIZE = new_sysize;
8066 DXSIZE = new_dxsize;
8067 DYSIZE = new_dysize;
8068 VXSIZE = new_vxsize;
8069 VYSIZE = new_vysize;
8070 EXSIZE = new_exsize;
8071 EYSIZE = new_eysize;
8072 REAL_SX = new_real_sx;
8073 REAL_SY = new_real_sy;
8074 FULL_SXSIZE = new_full_sxsize;
8075 FULL_SYSIZE = new_full_sysize;
8076 TILESIZE_VAR = new_tilesize_var;
8078 init_gfx_buffers = TRUE;
8079 init_gadgets_and_toons = TRUE;
8081 // printf("::: viewports: init_gfx_buffers\n");
8082 // printf("::: viewports: init_gadgets_and_toons\n");
8085 if (init_gfx_buffers)
8087 // printf("::: init_gfx_buffers\n");
8089 SCR_FIELDX = new_scr_fieldx_buffers;
8090 SCR_FIELDY = new_scr_fieldy_buffers;
8094 SCR_FIELDX = new_scr_fieldx;
8095 SCR_FIELDY = new_scr_fieldy;
8097 gfx.drawing_area_changed = drawing_area_changed;
8099 SetDrawDeactivationMask(REDRAW_NONE);
8100 SetDrawBackgroundMask(REDRAW_FIELD);
8103 if (init_video_buffer)
8105 // printf("::: init_video_buffer\n");
8107 InitVideoBuffer(WIN_XSIZE, WIN_YSIZE, DEFAULT_DEPTH, setup.fullscreen);
8110 if (init_gadgets_and_toons)
8112 // printf("::: init_gadgets_and_toons\n");
8118 if (init_em_graphics)
8120 InitGraphicInfo_EM();