+ return InitEngineRandom_EM(seed);
+ else
+ return InitEngineRandom_RND(seed);
+}
+
+#if 1
+static struct Mapping_EM_to_RND_object object_mapping[TILE_MAX];
+static struct Mapping_EM_to_RND_player player_mapping[MAX_PLAYERS][SPR_MAX];
+#endif
+
+inline static int get_effective_element_EM(int tile, int frame_em)
+{
+ int element = object_mapping[tile].element_rnd;
+ int action = object_mapping[tile].action;
+ boolean is_backside = object_mapping[tile].is_backside;
+ boolean action_removing = (action == ACTION_DIGGING ||
+ action == ACTION_SNAPPING ||
+ action == ACTION_COLLECTING);
+
+ if (frame_em < 7)
+ {
+ switch (tile)
+ {
+ case Yacid_splash_eB:
+ case Yacid_splash_wB:
+ return (frame_em > 5 ? EL_EMPTY : element);
+
+ default:
+ return element;
+ }
+ }
+ else /* frame_em == 7 */
+ {
+ switch (tile)
+ {
+ case Yacid_splash_eB:
+ case Yacid_splash_wB:
+ return EL_EMPTY;
+
+ case Yemerald_stone:
+ return EL_EMERALD;
+
+ case Ydiamond_stone:
+ return EL_ROCK;
+
+ case Xdrip_stretch:
+ case Xdrip_stretchB:
+ case Ydrip_s1:
+ case Ydrip_s1B:
+ case Xball_1B:
+ case Xball_2:
+ case Xball_2B:
+ case Yball_eat:
+ case Ykey_1_eat:
+ case Ykey_2_eat:
+ case Ykey_3_eat:
+ case Ykey_4_eat:
+ case Ykey_5_eat:
+ case Ykey_6_eat:
+ case Ykey_7_eat:
+ case Ykey_8_eat:
+ case Ylenses_eat:
+ case Ymagnify_eat:
+ case Ygrass_eat:
+ case Ydirt_eat:
+ case Xsand_stonein_1:
+ case Xsand_stonein_2:
+ case Xsand_stonein_3:
+ case Xsand_stonein_4:
+ return element;
+
+ default:
+ return (is_backside || action_removing ? EL_EMPTY : element);
+ }
+ }
+}
+
+inline static boolean check_linear_animation_EM(int tile)
+{
+ switch (tile)
+ {
+ case Xsand_stonesand_1:
+ case Xsand_stonesand_quickout_1:
+ case Xsand_sandstone_1:
+ case Xsand_stonein_1:
+ case Xsand_stoneout_1:
+ case Xboom_1:
+ case Xdynamite_1:
+ case Ybug_w_n:
+ case Ybug_n_e:
+ case Ybug_e_s:
+ case Ybug_s_w:
+ case Ybug_e_n:
+ case Ybug_s_e:
+ case Ybug_w_s:
+ case Ybug_n_w:
+ case Ytank_w_n:
+ case Ytank_n_e:
+ case Ytank_e_s:
+ case Ytank_s_w:
+ case Ytank_e_n:
+ case Ytank_s_e:
+ case Ytank_w_s:
+ case Ytank_n_w:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+inline static void set_crumbled_graphics_EM(struct GraphicInfo_EM *g_em,
+ boolean has_crumbled_graphics,
+ int crumbled, int sync_frame)
+{
+ /* if element can be crumbled, but certain action graphics are just empty
+ space (like instantly snapping sand to empty space in 1 frame), do not
+ treat these empty space graphics as crumbled graphics in EMC engine */
+ if (crumbled == IMG_EMPTY_SPACE)
+ has_crumbled_graphics = FALSE;
+
+ if (has_crumbled_graphics)
+ {
+ struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
+ int frame_crumbled = getAnimationFrame(g_crumbled->anim_frames,
+ g_crumbled->anim_delay,
+ g_crumbled->anim_mode,
+ g_crumbled->anim_start_frame,
+ sync_frame);
+
+ getGraphicSource(crumbled, frame_crumbled, &g_em->crumbled_bitmap,
+ &g_em->crumbled_src_x, &g_em->crumbled_src_y);
+
+ g_em->crumbled_border_size = graphic_info[crumbled].border_size;
+
+ g_em->has_crumbled_graphics = TRUE;
+ }
+ else
+ {
+ g_em->crumbled_bitmap = NULL;
+ g_em->crumbled_src_x = 0;
+ g_em->crumbled_src_y = 0;
+ g_em->crumbled_border_size = 0;
+
+ g_em->has_crumbled_graphics = FALSE;
+ }
+}
+
+void ResetGfxAnimation_EM(int x, int y, int tile)
+{
+ GfxFrame[x][y] = 0;
+}
+
+void SetGfxAnimation_EM(struct GraphicInfo_EM *g_em,
+ int tile, int frame_em, int x, int y)
+{
+ int action = object_mapping[tile].action;
+#if 1
+ int direction = object_mapping[tile].direction;
+ int effective_element = get_effective_element_EM(tile, frame_em);
+ int graphic = (direction == MV_NONE ?
+ el_act2img(effective_element, action) :
+ el_act_dir2img(effective_element, action, direction));
+ struct GraphicInfo *g = &graphic_info[graphic];
+ int sync_frame;
+#endif
+ boolean action_removing = (action == ACTION_DIGGING ||
+ action == ACTION_SNAPPING ||
+ action == ACTION_COLLECTING);
+ boolean action_moving = (action == ACTION_FALLING ||
+ action == ACTION_MOVING ||
+ action == ACTION_PUSHING ||
+ action == ACTION_EATING ||
+ action == ACTION_FILLING ||
+ action == ACTION_EMPTYING);
+ boolean action_falling = (action == ACTION_FALLING ||
+ action == ACTION_FILLING ||
+ action == ACTION_EMPTYING);
+
+#if 0
+ if (tile == Xsand_stonesand_1 ||
+ tile == Xsand_stonesand_2 ||
+ tile == Xsand_stonesand_3 ||
+ tile == Xsand_stonesand_4)
+ printf("::: 1: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
+#endif
+
+#if 1
+ if ((action_removing || check_linear_animation_EM(tile)) && frame_em == 0)
+ {
+ GfxFrame[x][y] = 0;
+
+ // printf("::: resetting... [%d]\n", tile);
+ }
+#else
+ if (action_removing || check_linear_animation_EM(tile))
+ {
+ GfxFrame[x][y] = frame_em;
+
+ // printf("::: resetting... [%d]\n", tile);
+ }
+#endif
+ else if (action_moving)
+ {
+ boolean is_backside = object_mapping[tile].is_backside;
+
+ if (is_backside)
+ {
+ int direction = object_mapping[tile].direction;
+ int move_dir = (action_falling ? MV_DOWN : direction);
+
+ GfxFrame[x][y]++;
+
+ if (move_dir == MV_LEFT)
+ GfxFrame[x - 1][y] = GfxFrame[x][y];
+ else if (move_dir == MV_RIGHT)
+ GfxFrame[x + 1][y] = GfxFrame[x][y];
+ else if (move_dir == MV_UP)
+ GfxFrame[x][y - 1] = GfxFrame[x][y];
+ else if (move_dir == MV_DOWN)
+ GfxFrame[x][y + 1] = GfxFrame[x][y];
+ }
+ }
+ else
+ {
+ GfxFrame[x][y]++;
+
+ /* special case: animation for Xsand_stonesand_quickout_1/2 twice as fast */
+ if (tile == Xsand_stonesand_quickout_1 ||
+ tile == Xsand_stonesand_quickout_2)
+ GfxFrame[x][y]++;
+ }
+
+#if 0
+ if (tile == Xsand_stonesand_1 ||
+ tile == Xsand_stonesand_2 ||
+ tile == Xsand_stonesand_3 ||
+ tile == Xsand_stonesand_4)
+ printf("::: 2: quicksand frame %d [%d]\n", GfxFrame[x][y], tile);
+#endif
+
+#if 1
+ if (graphic_info[graphic].anim_global_sync)
+ sync_frame = FrameCounter;
+ else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
+ sync_frame = GfxFrame[x][y];
+ else
+ sync_frame = 0; /* playfield border (pseudo steel) */
+
+ SetRandomAnimationValue(x, y);
+
+ int frame = getAnimationFrame(g->anim_frames,
+ g->anim_delay,
+ g->anim_mode,
+ g->anim_start_frame,
+ sync_frame);
+
+ g_em->unique_identifier =
+ (graphic << 16) | ((frame % 8) << 12) | (g_em->width << 6) | g_em->height;
+#endif
+}
+
+void getGraphicSourceObjectExt_EM(struct GraphicInfo_EM *g_em,
+ int tile, int frame_em, int x, int y)
+{
+ int action = object_mapping[tile].action;
+ int direction = object_mapping[tile].direction;
+ int effective_element = get_effective_element_EM(tile, frame_em);
+ int graphic = (direction == MV_NONE ?
+ el_act2img(effective_element, action) :
+ el_act_dir2img(effective_element, action, direction));
+ int crumbled = (direction == MV_NONE ?
+ el_act2crm(effective_element, action) :
+ el_act_dir2crm(effective_element, action, direction));
+ int base_graphic = el_act2img(effective_element, ACTION_DEFAULT);
+ int base_crumbled = el_act2crm(effective_element, ACTION_DEFAULT);
+ boolean has_crumbled_graphics = (base_crumbled != base_graphic);
+ struct GraphicInfo *g = &graphic_info[graphic];
+#if 0
+ struct GraphicInfo *g_crumbled = &graphic_info[crumbled];
+#endif
+ int sync_frame;
+
+#if 0
+ if (frame_em == 0) /* reset animation frame for certain elements */
+ {
+ if (check_linear_animation_EM(tile))
+ GfxFrame[x][y] = 0;
+ }
+#endif
+
+ if (graphic_info[graphic].anim_global_sync)
+ sync_frame = FrameCounter;
+ else if (IN_FIELD(x, y, MAX_LEV_FIELDX, MAX_LEV_FIELDY))
+ sync_frame = GfxFrame[x][y];