Exemplo n.º 1
0
 def __init__(self, obj, routing_surface, orientation, *args, **kwargs):
     translation = self.get_translation(obj)
     self._tuned_orientation = orientation
     orientation = self.get_orientation(obj)
     if routing_surface == ROUTING_SURFACE_TERRAIN:
         routing_surface = obj.routing_surface
     elif routing_surface == ROUTING_SURFACE_OBJECT:
         routing_surface = obj.provided_routing_surface
     elif routing_surface == ROUTING_SURFACE_GLOBAL_OBJECT:
         routing_surface = SurfaceIdentifier(
             services.current_zone_id(), obj.routing_surface.secondary_id,
             SurfaceType.SURFACETYPE_OBJECT)
     elif routing_surface == ROUTING_SURFACE_OCEAN:
         routing_surface = SurfaceIdentifier(services.current_zone_id(), 0,
                                             SurfaceType.SURFACETYPE_POOL)
     override_level = kwargs.get('override_level')
     if override_level is not None:
         routing_surface = SurfaceIdentifier(routing_surface.primary_id,
                                             override_level,
                                             routing_surface.type)
     terrain_object = services.terrain_service.terrain_object()
     translation.y = terrain_object.get_routing_surface_height_at(
         translation.x, translation.z, routing_surface)
     super().__init__(translation,
                      orientation=orientation,
                      routing_surface=routing_surface)
Exemplo n.º 2
0
 def get_edge_constraint(self,
                         constraint_width=1.0,
                         inward_dir=False,
                         return_constraint_list=False,
                         los_reference_point=DEFAULT,
                         sim=None):
     constraint_list = []
     if inward_dir:
         constraint_list.append(SWIM_AT_NONE_CONSTRAINT)
         routing_surface = SurfaceIdentifier(services.current_zone_id(), 0,
                                             SurfaceType.SURFACETYPE_POOL)
         interval = WaterDepthIntervals.SWIM
     else:
         constraint_list.append(STAND_AT_NONE_CONSTRAINT)
         routing_surface = SurfaceIdentifier(services.current_zone_id(), 0,
                                             SurfaceType.SURFACETYPE_WORLD)
         interval = WaterDepthIntervals.WET
     constraint = OceanStartLocationConstraint.create_simple_constraint(
         interval,
         constraint_width,
         sim,
         routing_surface=routing_surface,
         los_reference_point=los_reference_point)
     if not constraint.valid:
         constraint = ANYWHERE
     if return_constraint_list:
         constraint_list.append(constraint)
         return constraint_list
     for other_constraint in constraint_list:
         constraint = constraint.intersect(other_constraint)
     return constraint
Exemplo n.º 3
0
 def __call__(self, obj):
     routing_surface = obj.routing_surface
     level = routing_surface.secondary_id
     if self.level_override is not None:
         level = self.level_override
     return SurfaceIdentifier(routing_surface.primary_id, level,
                              self.surface_type)
Exemplo n.º 4
0
 def get_nearest_constraint_start_location(self, species, age,
                                           start_position,
                                           interval: WaterDepthIntervals):
     surface_type = None
     if interval == WaterDepthIntervals.WALK or interval == WaterDepthIntervals.WET or interval == WaterDepthIntervals.WADE:
         surface_type = SurfaceType.SURFACETYPE_WORLD
     elif interval == WaterDepthIntervals.SWIM:
         surface_type = SurfaceType.SURFACETYPE_POOL
     else:
         logger.error('Unhandled water depth interval {}'.format(interval))
     surface_id = SurfaceIdentifier(services.current_zone_id(), 0,
                                    surface_type)
     if interval == WaterDepthIntervals.WALK:
         interval = WaterDepthIntervals.WADE
     key = (species, age, interval)
     if key not in self._constraint_starts:
         return
     else:
         starts = self._constraint_starts[key]
         if starts:
             best_start = starts[0]
             best_distSq = (start_position -
                            best_start.translation).magnitude_squared()
             for start in starts[1:]:
                 distSq = (start_position -
                           start.translation).magnitude_squared()
                 if distSq < best_distSq:
                     best_start = start
                     best_distSq = distSq
             return Location(best_start, surface_id)
Exemplo n.º 5
0
 def place_puddle(self, target, max_distance, ids_to_ignore=DEFAULT):
     destroy_puddle = True
     try:
         if ids_to_ignore is DEFAULT:
             ids_to_ignore = (self.id,)
         else:
             ids_to_ignore.append(self.id)
         flags = placement.FGLSearchFlag.ALLOW_GOALS_IN_SIM_POSITIONS
         flags = flags | placement.FGLSearchFlag.ALLOW_GOALS_IN_SIM_INTENDED_POSITIONS
         flags = flags | placement.FGLSearchFlag.STAY_IN_SAME_CONNECTIVITY_GROUP
         if target.is_on_active_lot():
             flags = flags | placement.FGLSearchFlag.SHOULD_TEST_BUILDBUY
         else:
             flags = flags | placement.FGLSearchFlag.SHOULD_TEST_ROUTING
             flags = flags | placement.FGLSearchFlag.USE_SIM_FOOTPRINT
         flags = flags | placement.FGLSearchFlag.CALCULATE_RESULT_TERRAIN_HEIGHTS
         flags = flags | placement.FGLSearchFlag.DONE_ON_MAX_RESULTS
         radius_target = target
         while radius_target.parent is not None:
             radius_target = radius_target.parent
         if radius_target.is_part:
             radius_target = radius_target.part_owner
         routing_surface = target.routing_surface
         routing_surface = SurfaceIdentifier(routing_surface.primary_id, routing_surface.secondary_id, SurfaceType.SURFACETYPE_WORLD)
         starting_location = placement.create_starting_location(position=target.position + target.forward*radius_target.object_radius, orientation=sims4.random.random_orientation(), routing_surface=routing_surface)
         fgl_context = placement.create_fgl_context_for_object(starting_location, self, search_flags=flags, ignored_object_ids=ids_to_ignore, max_distance=max_distance)
         (position, orientation) = placement.find_good_location(fgl_context)
         if position is not None:
             destroy_puddle = False
             self.place_puddle_at(position, orientation, routing_surface)
             return True
         return False
     finally:
         if destroy_puddle:
             self.destroy(source=self, cause='Failed to place puddle.')
Exemplo n.º 6
0
 def get_objects_gen(self, resolver):
     lot = services.active_lot()
     pos = lot.get_lot_position(self.lot_location_strategy)
     from objects.terrain import TerrainPoint
     yield TerrainPoint.create_for_position_and_orientation(
         position=pos,
         routing_surface=SurfaceIdentifier(services.current_zone_id(), 0,
                                           SurfaceType.SURFACETYPE_WORLD))
Exemplo n.º 7
0
def test_surface_height(x: float = 0.0,
                        y: float = 0.0,
                        z: float = 0.0,
                        _connection=None):
    terrain_height = get_terrain_height(
        x, z, SurfaceIdentifier(0, 0, SurfaceType.SURFACETYPE_WORLD))
    sims4.commands.output('Terrain Surface: {}'.format(terrain_height),
                          _connection)
    object_height = get_terrain_height(
        x, z, SurfaceIdentifier(0, 0, SurfaceType.SURFACETYPE_OBJECT))
    sims4.commands.output('Object Surface: {}'.format(object_height),
                          _connection)
    water_height = get_terrain_height(
        x, z, SurfaceIdentifier(0, 0, SurfaceType.SURFACETYPE_POOL))
    sims4.commands.output('Water Surface: {}'.format(water_height),
                          _connection)
    difference = water_height - terrain_height
    sims4.commands.output('Water Height: {}'.format(difference), _connection)
Exemplo n.º 8
0
 def _entered_pipeline(self):
     if self.carry_target is not None:
         fgl_flags = FGLSearchFlag.STAY_IN_CURRENT_BLOCK | FGLSearchFlag.STAY_IN_SAME_CONNECTIVITY_GROUP | FGLSearchFlag.SHOULD_TEST_ROUTING | FGLSearchFlag.CALCULATE_RESULT_TERRAIN_HEIGHTS | FGLSearchFlag.DONE_ON_MAX_RESULTS | FGLSearchFlag.SHOULD_RAYTEST
         fgl_kwargs = {
             'raytest_radius': self.raytest_radius,
             'raytest_start_offset': self.raytest_offset.lower_bound,
             'raytest_end_offset': self.raytest_offset.upper_bound,
             'ignored_object_ids': {sim.id
                                    for sim in self.required_sims()},
             'positioning_type': JigPositioning.RelativeToSimA
         }
         pick = self.context.pick
         if pick is not None and pick.routing_surface.type == SurfaceType.SURFACETYPE_POOL:
             swim_constraint = WaterDepthIntervalConstraint.create_water_depth_interval_constraint(
                 self.target, WaterDepthIntervals.SWIM)
             pick_location = sims4.math.Location(
                 sims4.math.Transform(pick.location), pick.routing_surface)
             if swim_constraint.is_location_water_depth_valid(
                     pick_location):
                 loc_a = pick_location
                 self._routing_surface = pick.routing_surface
             else:
                 self._routing_surface = SurfaceIdentifier(
                     pick.routing_surface.primary_id,
                     pick.routing_surface.secondary_id,
                     SurfaceType.SURFACETYPE_WORLD)
                 loc_a = pick_location.clone(
                     routing_surface=self._routing_surface)
             fgl_kwargs.update({
                 'search_flags':
                 fgl_flags,
                 'restrictions':
                 (sims4.geometry.RelativeFacingRange(self.sim.position,
                                                     0), )
             })
             self.setup_final_transforms(loc_a, **fgl_kwargs)
         else:
             self._starting_location = self.find_starting_location()
             if self._starting_location is not None:
                 check_on_lot = self.sim.is_on_active_lot()
                 if check_on_lot:
                     fgl_flags = fgl_flags | FGLSearchFlag.STAY_IN_LOT
                 loc_a = self._starting_location
                 fgl_flags |= FGLSearchFlag.SPIRAL_INWARDS
                 fgl_kwargs.update({
                     'max_distance':
                     self.placement_distance.upper_bound,
                     'min_distance':
                     self.placement_distance.lower_bound,
                     'restrictions': (sims4.geometry.RelativeFacingRange(
                         loc_a.transform.translation, 0), ),
                     'search_flags':
                     fgl_flags
                 })
                 self.setup_final_transforms(loc_a, **fgl_kwargs)
     return super()._entered_pipeline()
Exemplo n.º 9
0
 def move_ocean(ocean):
     zone = services.current_zone()
     terrain_center = zone.lot.center
     location = sims4.math.Location(
         sims4.math.Transform(
             translation=terrain_center,
             orientation=sims4.math.Quaternion.IDENTITY()),
         routing_surface=SurfaceIdentifier(
             zone.id, 0, SurfaceType.SURFACETYPE_WORLD))
     ocean.location = location
Exemplo n.º 10
0
    def find_starting_location(self):
        if self.carry_target is not None and self.minimum_requirement_jig is not None:
            fgl_flags = FGLSearchFlag.STAY_IN_CONNECTED_CONNECTIVITY_GROUP | FGLSearchFlag.SHOULD_TEST_ROUTING | FGLSearchFlag.CALCULATE_RESULT_TERRAIN_HEIGHTS | FGLSearchFlag.DONE_ON_MAX_RESULTS
            check_on_lot = self.sim.is_on_active_lot()
            if check_on_lot:
                fgl_flags = fgl_flags | FGLSearchFlag.STAY_IN_LOT
            fgl_kwargs = {
                'ignored_object_ids': {sim.id
                                       for sim in self.required_sims()},
                'positioning_type': JigPositioning.RelativeToSimA
            }
            loc_a = self.sim.location.duplicate()
            fgl_kwargs.update({'search_flags': fgl_flags})
            loc_b = loc_a.duplicate()
            lot = services.current_zone().lot

            def find_a_starting_location():
                for (transform_a, transform_b, routing_surface,
                     _) in self.minimum_requirement_jig.get_transforms_gen(
                         self.sim,
                         self.carry_target,
                         actor_loc=loc_a,
                         target_loc=loc_b,
                         fgl_kwargs=fgl_kwargs):
                    if not check_on_lot or lot.is_position_on_lot(
                            transform_a.translation):
                        if not lot.is_position_on_lot(transform_b.translation):
                            continue
                        return sims4.math.Location(transform_a,
                                                   routing_surface)
                    else:
                        return
                else:
                    return

            use_pool_surface = loc_a.routing_surface.type == SurfaceType.SURFACETYPE_POOL or 0 < get_water_depth_at_location(
                loc_a)
            if use_pool_surface:
                interval = WaterDepthIntervals.SWIM
                if loc_a.routing_surface.type != SurfaceType.SURFACETYPE_POOL:
                    self._routing_surface = SurfaceIdentifier(
                        loc_a.routing_surface.primary_id,
                        loc_a.routing_surface.secondary_id,
                        SurfaceType.SURFACETYPE_POOL)
                    loc_a = loc_a.clone(routing_surface=self._routing_surface)
            else:
                interval = WaterDepthIntervals.WALK
            fgl_kwargs = self._update_water_depth_requirements(
                self.sim, self.target, interval, **fgl_kwargs)
            start_loc = find_a_starting_location()
            if start_loc is not None:
                return start_loc
        return self.sim.location.duplicate()
Exemplo n.º 11
0
 def get_portal_locations(self, obj):
     shell = self._get_shell()
     if shell is None:
         return ()
     elevator_pos = self._get_bone_position(obj, self.elevator_bone_name)
     if elevator_pos is None:
         return ()
     shell_pos = self._get_bone_position(shell, self.shell_bone_name)
     if shell_pos is None:
         return ()
     elevator_loc = Location(elevator_pos, routing_surface=obj.routing_surface)
     shell_routing_surface = SurfaceIdentifier(services.current_zone_id(), 0, SurfaceType.SURFACETYPE_WORLD)
     shell_loc = Location(shell_pos, routing_surface=shell_routing_surface)
     return ((shell_loc, elevator_loc, elevator_loc, shell_loc, 0),)
Exemplo n.º 12
0
 def get_routes_gen(self):
     routing_surface = self._obj.routing_surface
     routing_surface = SurfaceIdentifier(routing_surface.primary_id,
                                         routing_surface.secondary_id,
                                         self.surface_type_override)
     starting_location = placement.create_starting_location(
         transform=self._obj.location.transform,
         routing_surface=routing_surface)
     fgl_context = placement.create_fgl_context_for_object(
         starting_location, self._obj)
     (position, orientation) = find_good_location(fgl_context)
     if self.surface_type_override is not None and position is None or orientation is None:
         return False
         yield
     if vector3_almost_equal(position, starting_location.position):
         return True
         yield
     goal = Goal(
         routing.Location(position, orientation,
                          starting_location.routing_surface))
     routing_context = self._obj.get_routing_context()
     route = routing.Route(self._obj.routing_location, (goal, ),
                           routing_context=routing_context)
     yield route
Exemplo n.º 13
0
    def _create_all_transforms_and_portals_for_initial_transforms(
            self,
            initial_transforms,
            lot_transforms=False,
            prior_lengths=None,
            store_portal_ids=None):
        portal_component = self.get_component(PORTAL_COMPONENT)
        if portal_component is None:
            return

        def _store_transforms(species, ages, interval, transforms):
            for age in ages:
                key = (species, age, interval)
                if key in self._constraint_starts:
                    if prior_lengths is not None:
                        prior_lengths[key] = len(self._constraint_starts[key])
                    self._constraint_starts[key].extend(transforms)
                else:
                    if prior_lengths is not None:
                        prior_lengths[key] = 0
                    self._constraint_starts[key] = transforms

        routing_surface = SurfaceIdentifier(services.current_zone_id(), 0,
                                            SurfaceType.SURFACETYPE_WORLD)
        edge_transforms = adjust_locations_for_coastline(initial_transforms)

        def _get_water_depth_at_edge(i):
            transform = edge_transforms[i]
            translation = transform.translation + transform.orientation.transform_vector(
                Ocean.EDGE_TEST_POINT_OFFSET)
            return get_water_depth(translation.x, translation.z)

        for (species, age_data) in OceanTuning.OCEAN_DATA.items():
            required_pack = SpeciesExtended.get_required_pack(species)
            if required_pack is not None and not is_available_pack(
                    required_pack):
                continue
            for age_ocean_data in age_data:
                ocean_data = age_ocean_data.ocean_data
                beach_portal = ocean_data.beach_portal_data
                wading_depth = ocean_data.wading_interval.lower_bound
                max_wading_depth = wading_depth + ocean_data.water_depth_error
                swim_depth = ocean_data.wading_interval.upper_bound
                min_swim_depth = swim_depth - ocean_data.water_depth_error
                transforms = adjust_locations_for_target_water_depth(
                    wading_depth, ocean_data.water_depth_error,
                    initial_transforms)
                wading_transforms = []
                for i in range(len(transforms) - 1):
                    transform = transforms[i]
                    if transform.translation == VECTOR3_ZERO:
                        depth = _get_water_depth_at_edge(i)
                        if depth <= max_wading_depth:
                            wading_transforms.append(edge_transforms[i])
                            wading_transforms.append(transform)
                    else:
                        wading_transforms.append(transform)
                transforms = adjust_locations_for_target_water_depth(
                    swim_depth, ocean_data.water_depth_error,
                    initial_transforms)
                portal_transforms = []
                for i in range(len(transforms) - 1):
                    transform = transforms[i]
                    if transform.translation == VECTOR3_ZERO:
                        depth = _get_water_depth_at_edge(i)
                        if min_swim_depth <= depth:
                            edge_transform = edge_transforms[i]
                            translation = edge_transform.translation + edge_transform.orientation.transform_vector(
                                Ocean.EDGE_PORTAL_BACKSET)
                            portal_transforms.append(
                                Transform(translation,
                                          edge_transform.orientation))
                    else:
                        portal_transforms.append(transform)
                _store_transforms(species, age_ocean_data.ages,
                                  WaterDepthIntervals.WET,
                                  edge_transforms.copy())
                _store_transforms(species, age_ocean_data.ages,
                                  WaterDepthIntervals.WADE, wading_transforms)
                _store_transforms(species, age_ocean_data.ages,
                                  WaterDepthIntervals.SWIM, portal_transforms)
                if beach_portal is None:
                    pass
                else:
                    if lot_transforms:
                        portal_transforms = self._reorient_lot_transforms(
                            portal_transforms)
                    portal_creation_mask = SpeciesExtended.get_portal_flag(
                        species)
                    for portal_transform in portal_transforms:
                        portal_location = Location(
                            portal_transform, routing_surface=routing_surface)
                        portal_ids = portal_component.add_custom_portal(
                            OceanPoint(portal_location), beach_portal,
                            portal_creation_mask)
                        add_portals = []
                        remove_portals = []
                        for portal_id in portal_ids:
                            portal_instance = portal_component.get_portal_by_id(
                                portal_id)
                            if portal_instance is not None:
                                location = None
                                if portal_id == portal_instance.there:
                                    location = portal_instance.there_entry
                                elif portal_id == portal_instance.back:
                                    location = portal_instance.back_exit
                                if location and build_buy.is_location_natural_ground(
                                        location.position,
                                        location.routing_surface.secondary_id):
                                    add_portals.append(portal_id)
                                else:
                                    remove_portals.append(portal_id)
                        if remove_portals:
                            portal_component.remove_custom_portals(
                                remove_portals)
                        if add_portals and store_portal_ids is not None:
                            store_portal_ids.extend(add_portals)
Exemplo n.º 14
0
 def _get_jig_transforms_gen(cls,
                             initiating_sim,
                             target_sim,
                             picked_object=None,
                             participant_slot_overrides=None):
     slot_map = cls.participant_slot_map if participant_slot_overrides is None else participant_slot_overrides
     actor_slot_index = slot_map.get(ParticipantType.Actor,
                                     cls.DEFAULT_SLOT_INDEX_ACTOR)
     target_slot_index = slot_map.get(ParticipantType.TargetSim,
                                      cls.DEFAULT_SLOT_INDEX_TARGET)
     if cls._can_picked_object_be_jig(picked_object):
         try:
             (actor_transform, target_transform,
              routing_surface) = get_two_person_transforms_for_jig(
                  picked_object.definition, picked_object.transform,
                  picked_object.routing_surface, actor_slot_index,
                  target_slot_index)
             yield (actor_transform, target_transform, routing_surface, ())
             return
         except RuntimeError:
             pass
     fallback_routing_surface = None
     if initiating_sim.routing_surface != target_sim.routing_surface:
         if initiating_sim.routing_surface.type == routing.SurfaceType.SURFACETYPE_WORLD:
             fallback_routing_surface = initiating_sim.routing_surface
         else:
             fallback_routing_surface = target_sim.routing_surface
     fallback_starting_position = None
     stay_in_connectivity_group = True
     ignore_restrictions = False
     if target_sim is not None:
         if target_sim.routing_surface.type == SurfaceType.SURFACETYPE_POOL:
             fallback_routing_surface = SurfaceIdentifier(
                 target_sim.routing_surface.primary_id,
                 target_sim.routing_surface.secondary_id,
                 SurfaceType.SURFACETYPE_WORLD)
             ocean = services.terrain_service.ocean_object()
             if not ocean is None:
                 if not target_sim.in_pool:
                     if not services.active_lot().is_position_on_lot(
                             target_sim.position):
                         extended_species = target_sim.extended_species
                         age = target_sim.age
                         start_location = ocean.get_nearest_constraint_start_location(
                             extended_species, age, target_sim.position,
                             WaterDepthIntervals.WET)
                         if start_location is not None:
                             fallback_starting_position = start_location.transform.translation
             stay_in_connectivity_group = False
             ignore_restrictions = True
     reference_routing_surface = initiating_sim.routing_surface if target_sim is None else target_sim.routing_surface
     (min_water_depth, max_water_depth
      ) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(
          reference_routing_surface, initiating_sim)
     if target_sim is not None:
         (min_water_depth, max_water_depth
          ) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(
              reference_routing_surface, target_sim, min_water_depth,
              max_water_depth)
     if fallback_routing_surface is not None:
         (fallback_min_water_depth, fallback_max_water_depth
          ) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(
              fallback_routing_surface, initiating_sim)
         if target_sim is not None:
             (fallback_min_water_depth, fallback_max_water_depth
              ) = OceanTuning.make_depth_bounds_safe_for_surface_and_sim(
                  fallback_routing_surface, target_sim,
                  fallback_min_water_depth, fallback_max_water_depth)
     else:
         fallback_min_water_depth = None
         fallback_max_water_depth = None
     yield from cls.jig.get_transforms_gen(
         initiating_sim,
         target_sim,
         actor_slot_index=actor_slot_index,
         target_slot_index=target_slot_index,
         stay_outside=cls.stay_outside,
         fallback_routing_surface=fallback_routing_surface,
         fallback_min_water_depth=fallback_min_water_depth,
         fallback_max_water_depth=fallback_max_water_depth,
         fallback_starting_position=fallback_starting_position,
         stay_in_connectivity_group=stay_in_connectivity_group,
         ignore_restrictions=ignore_restrictions,
         min_water_depth=min_water_depth,
         max_water_depth=max_water_depth)
Exemplo n.º 15
0
 def _fixup_pool_surface(self):
     if (self.item_location == ItemLocation.FROM_WORLD_FILE or self.item_location == ItemLocation.FROM_CONDITIONAL_LAYER) and (self.routing_surface.type != SurfaceType.SURFACETYPE_POOL and build_buy.PlacementFlags.REQUIRES_WATER_SURFACE & build_buy.get_object_placement_flags(self.definition.id)) and get_water_depth_at_location(self.location) > 0:
         routing_surface = self.routing_surface
         self.set_location(self.location.clone(routing_surface=SurfaceIdentifier(routing_surface.primary_id, routing_surface.secondary_id, SurfaceType.SURFACETYPE_POOL)))
Exemplo n.º 16
0
 def _try_place_object_internal(self,
                                obj,
                                target_obj,
                                resolver,
                                ignored_object_ids=None,
                                **kwargs):
     offset_tuning = self.initial_location_offset
     default_offset = sims4.math.Vector3(offset_tuning.default_offset.x,
                                         offset_tuning.default_offset.y,
                                         offset_tuning.default_offset.z)
     x_range = offset_tuning.x_randomization_range
     z_range = offset_tuning.z_randomization_range
     start_orientation = sims4.random.random_orientation()
     if x_range is not None:
         x_axis = start_orientation.transform_vector(
             sims4.math.Vector3.X_AXIS())
         default_offset += x_axis * random.uniform(x_range.lower_bound,
                                                   x_range.upper_bound)
     if z_range is not None:
         z_axis = start_orientation.transform_vector(
             sims4.math.Vector3.Z_AXIS())
         default_offset += z_axis * random.uniform(z_range.lower_bound,
                                                   z_range.upper_bound)
     offset = sims4.math.Transform(default_offset,
                                   sims4.math.Quaternion.IDENTITY())
     start_position = sims4.math.Transform.concatenate(
         offset, target_obj.transform).translation
     routing_surface = target_obj.routing_surface
     active_lot = services.active_lot()
     search_flags = FGLSearchFlag.CALCULATE_RESULT_TERRAIN_HEIGHTS | FGLSearchFlag.DONE_ON_MAX_RESULTS
     if self.surface_type_override is not None:
         routing_surface = SurfaceIdentifier(routing_surface.primary_id,
                                             routing_surface.secondary_id,
                                             self.surface_type_override)
     else:
         search_flags |= FGLSearchFlag.SHOULD_TEST_ROUTING
     if self.ignore_sim_positions:
         search_flags |= FGLSearchFlag.ALLOW_GOALS_IN_SIM_POSITIONS | FGLSearchFlag.ALLOW_GOALS_IN_SIM_INTENDED_POSITIONS
     if self.in_same_room:
         search_flags |= FGLSearchFlag.STAY_IN_CURRENT_BLOCK
     if self.stay_in_connected_connectivity_group:
         search_flags |= FGLSearchFlag.STAY_IN_CONNECTED_CONNECTIVITY_GROUP
     if self.stay_outside_placement:
         search_flags |= FGLSearchFlag.STAY_OUTSIDE
     raytest_kwargs = {}
     if self.raytest:
         search_flags |= FGLSearchFlag.SHOULD_RAYTEST
         raytest_kwargs.update({
             'raytest_radius':
             self.raytest.raytest_radius,
             'raytest_start_offset':
             self.raytest.raytest_start_height_offset,
             'raytest_end_offset':
             self.raytest.raytest_end_height_offset
         })
         if self.raytest.starting_position is not None:
             raytest_target = resolver.get_participant(
                 self.raytest.starting_position)
             if raytest_target is not None:
                 if raytest_target.is_sim:
                     raytest_target = raytest_target.get_sim_instance(
                         allow_hidden_flags=ALL_HIDDEN_REASONS)
                 raytest_kwargs[
                     'raytest_start_point_override'] = raytest_target.transform.translation
     restrictions = None
     if self.facing is not None:
         if self.facing.target is None:
             facing_target = target_obj
         else:
             facing_target = resolver.get_participant(self.facing.target)
         if facing_target is not None:
             restriction = sims4.geometry.RelativeFacingRange(
                 facing_target.position, self.facing.angle)
             restrictions = (restriction, )
     terrain_tags = list(self.terrain_tags) if self.terrain_tags else []
     if self.allow_off_lot_placement and not active_lot.is_position_on_lot(
             start_position):
         obj.location = sims4.math.Location(
             sims4.math.Transform(start_position, start_orientation),
             routing_surface)
         starting_location = create_starting_location(
             position=start_position,
             orientation=start_orientation,
             routing_surface=routing_surface)
         context = create_fgl_context_for_object_off_lot(
             starting_location,
             obj,
             terrain_tags=terrain_tags,
             search_flags=search_flags,
             ignored_object_ids=(obj.id, ),
             restrictions=restrictions,
             min_water_depth=self.min_water_depth,
             max_water_depth=self.max_water_depth,
             **raytest_kwargs)
     else:
         if not self.allow_off_lot_placement and not active_lot.is_position_on_lot(
                 start_position):
             return False
         if not self.ignore_bb_footprints:
             if routing_surface.type != SurfaceType.SURFACETYPE_WORLD:
                 search_flags |= FGLSearchFlag.SHOULD_TEST_BUILDBUY
             else:
                 search_flags |= FGLSearchFlag.SHOULD_TEST_BUILDBUY | FGLSearchFlag.STAY_IN_CURRENT_BLOCK
             if not active_lot.is_position_on_lot(start_position):
                 start_position = active_lot.get_default_position(
                     position=start_position)
             else:
                 position_inside_plex = self._get_plex_postion_for_object_creation(
                     start_position, routing_surface.secondary_id)
                 if position_inside_plex is not None:
                     start_position = position_inside_plex
         starting_location = create_starting_location(
             position=start_position,
             orientation=start_orientation,
             routing_surface=routing_surface)
         pos_increment_info = PositionIncrementInfo(
             position_increment=self.POSITION_INCREMENT,
             from_exception=False)
         context = create_fgl_context_for_object(
             starting_location,
             obj,
             terrain_tags=terrain_tags,
             search_flags=search_flags,
             ignored_object_ids=ignored_object_ids,
             position_increment_info=pos_increment_info,
             restrictions=restrictions,
             min_water_depth=self.min_water_depth,
             max_water_depth=self.max_water_depth,
             **raytest_kwargs)
     if self.perform_fgl_check:
         (translation, orientation) = find_good_location(context)
         if translation is not None:
             obj.move_to(routing_surface=routing_surface,
                         translation=translation,
                         orientation=orientation)
             return True
     elif starting_location is not None:
         obj.move_to(routing_surface=routing_surface,
                     translation=starting_location.position,
                     orientation=starting_location.orientation)
         return True
     return False