def teleport(self): if random.random() > self.chance_to_teleport: return if self.required_states is not None: for state in self.required_states: if not self.owner.state_value_active(state): return weights_and_commodities = [(obj_dict.weight, obj_dict.static_commodity, obj_dict.state_change) for obj_dict in self.objects_to_teleport_near] while weights_and_commodities: index = sims4.random._weighted(weights_and_commodities) (_, static_commodity, state_change) = weights_and_commodities.pop(index) motives = set() motives.add(static_commodity) all_objects = list(services.object_manager().valid_objects()) random.shuffle(all_objects) for obj in all_objects: if obj is self.owner: continue if obj.commodity_flags & motives: starting_location = placement.create_starting_location(position=obj.position) if self.owner.is_sim: fgl_context = placement.create_fgl_context_for_sim(starting_location, self.owner) else: fgl_context = placement.create_fgl_context_for_object(starting_location, self.owner) (position, orientation) = placement.find_good_location(fgl_context) if position is not None and orientation is not None: self.owner.transform = sims4.math.Transform(position, orientation) if state_change is not None: obj.set_state(state_change.state, state_change) break
def _do_behavior(self, *args, **kwargs): subject = self.interaction.get_participant(self.subject) target = self.interaction.get_participant(self.target) if subject is None or target is None: logger.error( 'Trying to run a PutNear basic extra with a None Subject and/or Target. subject:{}, target:{}', subject, target, owner='trevor') return starting_location = placement.create_starting_location( location=target.location) if subject.is_sim: fgl_context = placement.create_fgl_context_for_sim( starting_location, subject) else: fgl_context = placement.create_fgl_context_for_object( starting_location, subject) (translation, orientation) = placement.find_good_location(fgl_context) surface = target.routing_surface if translation is None: if self.fallback_to_spawn_point: zone = services.current_zone() fallback_point = zone.get_spawn_point(lot_id=zone.lot.lot_id) (translation, orientation) = fallback_point.next_spawn_spot() surface = fallback_point.routing_surface if translation is not None: subject.move_to(translation=translation, orientation=orientation or subject.orientation, routing_surface=surface, parent=None, joint_name_or_hash=None, slot_hash=0)
def _run_interaction_gen(self, timeline): if not self._teleporting: return True yield starting_loc = placement.create_starting_location( transform=self.target.transform, routing_surface=self.target.routing_surface) if self.target_jig is not None: fgl_context = placement.create_fgl_context_for_object( starting_loc, self.target_jig) else: fgl_context = placement.create_fgl_context_for_sim( starting_loc, self.sim) (position, orientation) = placement.find_good_location(fgl_context) if position is None: return False yield end_transform = sims4.math.Transform(position, orientation) self.sim.routing_component.on_slot = None ending_location = sims4.math.Location(end_transform, self.target.routing_surface) self.sim.location = ending_location self.sim.refresh_los_constraint() return True yield
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.')
def get_save_lot_coords_and_level(self): lot_coord_msg = LotCoord() parent = self.parent if parent is not None and parent.is_sim: parent.force_update_routing_location() starting_position = parent.position + parent.forward starting_location = placement.create_starting_location(position=starting_position, orientation=parent.orientation, routing_surface=self.location.world_routing_surface) fgl_context = placement.create_fgl_context_for_object(starting_location, self) (trans, orient) = placement.find_good_location(fgl_context) if trans is None: logger.warn('Unable to find good location to save object{}, which is parented to sim {} and cannot go into an inventory. Defaulting to location of sim.', self, parent) transform = parent.transform else: transform = sims4.math.Transform(trans, orient) if self.persistence_group == PersistenceGroups.OBJECT: transform = services.current_zone().lot.convert_to_lot_coordinates(transform) elif self.persistence_group == PersistenceGroups.OBJECT: transform = services.current_zone().lot.convert_to_lot_coordinates(self.transform) else: transform = self.transform lot_coord_msg.x = transform.translation.x lot_coord_msg.y = transform.translation.y lot_coord_msg.z = transform.translation.z lot_coord_msg.rot_x = transform.orientation.x lot_coord_msg.rot_y = transform.orientation.y lot_coord_msg.rot_z = transform.orientation.z lot_coord_msg.rot_w = transform.orientation.w if self.location.world_routing_surface is not None: level = self.location.level else: level = 0 return (lot_coord_msg, level)
def _on_fruit_fall_to_ground(self, fruit): plant = self.owner if fruit.parent is not plant: return False if not plant.is_on_active_lot(): return False starting_location = placement.create_starting_location( position=plant.position, routing_surface=plant.routing_surface) fgl_context = placement.create_fgl_context_for_object( starting_location, fruit, ignored_object_ids=(fruit.id, )) (position, orientation) = placement.find_good_location(fgl_context) if position is None or orientation is None: return False fruit.move_to(parent=None, translation=position, orientation=orientation, routing_surface=plant.routing_surface) owner = plant.get_household_owner_id() if owner is not None: fruit.set_household_owner_id(owner) decay_commodity = GardeningTuning.FRUIT_DECAY_COMMODITY fruit.set_stat_value( decay_commodity, GardeningTuning.FRUIT_DECAY_COMMODITY_DROPPED_VALUE) return True
def __call__(self, sim): def _abort(vehicle_obj): sim.allow_opacity_change = True sim.fade_in() if vehicle_obj is not None: vehicle_obj.destroy() vehicle = None if sim.sim_info.favorites_tracker is not None: favorites_tracker = sim.sim_info.favorites_tracker definition_manager = services.definition_manager() vehicle_def_id = favorites_tracker.get_favorite_definition_id( self.vehicle_obj_tag) if vehicle_def_id is not None: vehicle_def = definition_manager.get(vehicle_def_id) if vehicle_def is not None: vehicle = objects.system.create_object(vehicle_def) if vehicle is None: if self.fallback_vehicle_def is None: _abort(vehicle) return True vehicle = create_object(self.fallback_vehicle_def) if vehicle is None: _abort(vehicle) return True vehicle.set_household_owner_id(sim.household_id) starting_location = placement.create_starting_location( position=sim.position) fgl_context = placement.create_fgl_context_for_object( starting_location, vehicle) (position, orientation) = placement.find_good_location(fgl_context) if position is None or orientation is None: _abort(vehicle) return True vehicle.transform = sims4.math.Transform(position, orientation) result = vehicle.vehicle_component.push_drive_affordance( sim, priority=Priority.Critical) if result is None: _abort(vehicle) return True if result.interaction is None: logger.warn( "Vehicle's push drive affordance {} resulted in a None interaction. Result: {}.", vehicle.vehicle_component.drive_affordance, result, owner='jmorrow') _abort(vehicle) return True sim.fade_in() vehicle.claim() for situation in services.get_zone_situation_manager().get_all(): if sim in situation.all_sims_in_situation_gen(): situation.manage_vehicle(vehicle) break return True
def _place_object_on_ground(self, head_obj, source_obj): starting_location = create_starting_location( location=source_obj.location) search_flags = FGLSearchFlag.ALLOW_GOALS_IN_SIM_INTENDED_POSITIONS | FGLSearchFlag.ALLOW_GOALS_IN_SIM_POSITIONS fgl_context = placement.create_fgl_context_for_object( starting_location, head_obj, search_flags=search_flags, ignored_object_ids=(source_obj.id, )) (translation, orientation) = find_good_location(fgl_context) if translation is None or orientation is None: return False head_obj.move_to(translation=translation, orientation=orientation, routing_surface=source_obj.routing_surface) return True
def _restore_crate(self): if self._pet_crate_x is None: return obj = create_object(self.pet_crate_object_definition) if obj is None: return position = sims4.math.Vector3(float(self._pet_crate_x), float(self._pet_crate_y), float(self._pet_crate_z)) starting_location = placement.create_starting_location( position=position) fgl_context = placement.create_fgl_context_for_object( starting_location, obj, ignored_object_ids=(obj.id, )) (position, orientation) = placement.find_good_location(fgl_context) if position is not None and orientation is not None: obj.move_to(translation=position, orientation=orientation) else: obj.destroy()
def create_collectible_from_lightning_strike(location): create_tuning = LightningTuning.STRIKE_TERRAIN_TUNING.create_object_tuning weighted_items = [(def_weight.weight, def_weight.definition) for def_weight in create_tuning.definition_weights] obj_def = sims4.random.weighted_random_item(weighted_items) search_flags = placement.FGLSearchFlag.STAY_IN_CONNECTED_CONNECTIVITY_GROUP | placement.FGLSearchFlag.CALCULATE_RESULT_TERRAIN_HEIGHTS | placement.FGLSearchFlag.DONE_ON_MAX_RESULTS | placement.FGLSearchFlag.ALLOW_GOALS_IN_SIM_POSITIONS starting_location = placement.create_starting_location(location=location) fgl_context = placement.create_fgl_context_for_object(starting_location, obj_def, search_flags=search_flags) (new_position, new_orientation) = placement.find_good_location(fgl_context) if new_position is None or new_orientation is None: logger.info('No good location found for {} from a lightning strike at {}.', obj_def, location, owner='rmccord') return new_location = sims4.math.Location(sims4.math.Transform(new_position, new_orientation), location.routing_surface) created_obj = objects.system.create_object(obj_def) if created_obj is not None: created_obj.opacity = 0 created_obj.fade_in() created_obj.set_location(new_location) created_obj.set_household_owner_id(None)
def try_to_place_bassinet(position, routing_surface=None, **kwargs): starting_location = placement.create_starting_location( position=position, routing_surface=routing_surface) fgl_context = placement.create_fgl_context_for_object( starting_location, self, **kwargs) (translation, orientation) = placement.find_good_location(fgl_context) if translation is not None and orientation is not None: if is_active_zone_a_plex and ( routing_surface is None or plex_service.get_plex_zone_at_position( translation, routing_surface.secondary_id) is None): return False else: self.move_to(translation=translation, orientation=orientation) if routing_surface is not None: self.move_to(routing_surface=routing_surface) return True return False
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
def get_fgl_at_destination_for_teleport(cls, ideal_location, destination_object, destination_must_be_outside=False, ignore_connectivity=False): search_flags = placement.FGLSearchFlagsDefault if destination_must_be_outside: search_flags |= placement.FGLSearchFlag.STAY_OUTSIDE fgl_context = None if destination_object.is_sim: search_flags |= placement.FGLSearchFlagsDefaultForSim if ignore_connectivity: search_flags &= ~placement.FGLSearchFlag.STAY_IN_CONNECTED_CONNECTIVITY_GROUP fgl_context = placement.create_fgl_context_for_sim( ideal_location, destination_object, search_flags=search_flags) else: search_flags |= placement.FGLSearchFlagsDefaultForObject if ignore_connectivity: search_flags &= ~placement.FGLSearchFlag.STAY_IN_CONNECTED_CONNECTIVITY_GROUP fgl_context = placement.create_fgl_context_for_object( ideal_location, destination_object, search_flags=search_flags) if fgl_context is not None: return placement.find_good_location(fgl_context) return (None, None)
def _create_object_on_ground(self, spawner_data, max_distance, min_distance, force_initialization_spawn): source_object = self.owner spawn_list = list(spawner_data.object_reference) parent_loc_type = self._get_inherited_spawn_location_type() starting_location_tuning = spawner_data.spawner_option.starting_location if spawner_data.spawner_option.starting_location.location_type == SpawnerTuning.PORTAL_LOCATION: portal_component = self.owner.get_component(PORTAL_COMPONENT) if portal_component is None: logger.error( "Trying to spawn objects relative to a portal position and the spawner object ({}) doesn't have a portal component. No objects will be spawned.", self.owner) return portal_location = portal_component.get_portal_location_by_type( starting_location_tuning.portal_type, starting_location_tuning.portal_direction, starting_location_tuning.portal_location) if portal_location is None: logger.error( 'Unable to find a location relative to the specified portal type, location, and direction. No objects will be spawned.' ) return if starting_location_tuning.location_type == SpawnerTuning.PORTAL_LOCATION: starting_location = placement.create_starting_location( position=portal_location.position, routing_surface=portal_location.routing_surface) else: starting_location = placement.create_starting_location( position=source_object.position, routing_surface=source_object.routing_surface) for obj in spawn_list: created_obj_location = sims4.math.Location( sims4.math.Transform(source_object.position, source_object.orientation), source_object.routing_surface) if source_object.is_on_active_lot(): fgl_context = placement.create_fgl_context_for_object( starting_location, obj, test_buildbuy_allowed=False, max_distance=max_distance, min_distance=min_distance, height_tolerance=GlobalObjectSpawnerTuning. SPAWN_ON_GROUND_FGL_HEIGHT_TOLERANCE) else: restrictions = [ restriction(location=created_obj_location) for restriction in spawner_data.spawner_option.restrictions ] or None scoring_functions = [ placement_scoring(location=created_obj_location) for placement_scoring in spawner_data.spawner_option.placement_scoring ] or None ignored_object_ids = ( source_object.id, ) if not spawner_data.spawner_option.starting_location.consider_source_object_footprint else ( ) fgl_context = placement.create_fgl_context_for_object_off_lot( starting_location, None, location=created_obj_location, footprint=obj.definition.get_footprint(), max_distance=max_distance, min_distance=min_distance, height_tolerance=GlobalObjectSpawnerTuning. SPAWN_ON_GROUND_FGL_HEIGHT_TOLERANCE, restrictions=restrictions, scoring_functions=scoring_functions, ignored_object_ids=ignored_object_ids) (position, orientation) = placement.find_good_location(fgl_context) if position is not None: created_obj_location = sims4.math.Location( sims4.math.Transform(position, orientation), starting_location.routing_surface) created_obj = spawner_data.create_spawned_object( source_object, obj, loc_type=parent_loc_type) if created_obj is None: logger.error( 'SpawnerComponent: Spawner {} failed to create object: {}', source_object, obj, owner='shouse') return created_obj.location = created_obj_location created_obj.opacity = 0 if force_initialization_spawn: force_states = spawner_data.spawner_option.force_initialization_spawn created_obj.force_spawn_object( spawn_type=SpawnerTuning.SLOT_SPAWNER) else: force_states = spawner_data.spawner_option.force_states if force_states is not None: for force_state in force_states: created_obj.set_state(force_state.state, force_state) created_obj.fade_in() else: logger.info( 'SpawnerComponent: FGL failed, object {} will not spawn for spawner {}', obj.definition, source_object)
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
def _apply_to_subject_and_target(self, subject, target, resolver): if not self._fruits_to_sprout_from: return weighted_fruit_definitions = list( (weighted_fruit.weight.get_multiplier(resolver), weighted_fruit.fruit) for weighted_fruit in self._fruits_to_sprout_from) fruit_to_germinate = sims4.random.pop_weighted( weighted_fruit_definitions) parent_slot = None if not subject.is_terrain: runtime_slots = tuple(subject.get_runtime_slots_gen()) fruit_to_try = fruit_to_germinate fruit_to_germinate = None while fruit_to_germinate is None: for slot in runtime_slots: if not slot.empty: continue if slot.is_valid_for_placement(definition=fruit_to_try): fruit_to_germinate = fruit_to_try parent_slot = slot break if fruit_to_germinate is not None: break if not weighted_fruit_definitions: break fruit_to_try = sims4.random.pop_weighted( weighted_fruit_definitions) def post_add(obj): obj.transient = True obj.visibility = VisibilityState(visibility=False, inherits=False, enable_drop_shadow=False) created_fruit = create_object(fruit_to_germinate, post_add=post_add) if created_fruit is None: logger.error( f'Error occurred creating {fruit_to_germinate} in {self}') return if created_fruit.gardening_component is None: logger.error( f'{created_fruit} is a fruit with no fruit gardening component tuned in {self}' ) return if parent_slot is None: starting_location = placement.create_starting_location( position=subject.position, routing_surface=subject.routing_surface) fgl_context = placement.create_fgl_context_for_object( starting_location, created_fruit, ignored_object_ids=(created_fruit.id, )) (position, orientation) = placement.find_good_location(fgl_context) if position is None or orientation is None: logger.warn( f'Could not find good location for {created_fruit} using starting location {starting_location}' ) return created_fruit.move_to(translation=position, orientation=orientation, routing_surface=subject.routing_surface) else: parent_slot.add_child(created_fruit) created_plant = created_fruit.gardening_component.germinate() if not created_plant: logger.error(f'Failed to germinate {created_fruit}') return for state_to_set in self._states_to_set_on_plant: created_plant.set_state(state_to_set.state, state_to_set) if created_plant.gardening_component is None: logger.error( f'{created_plant} was germinated but had no gardening component!' ) return if resolver.interaction: resolver.interaction.context.create_target_override = created_plant