def _select_sims_from_results(self, results, sims_to_spawn): self._selected_sim_infos = [] global_blacklist = services.sim_filter_service().get_global_blacklist() for result in tuple(results): while result.sim_info.is_instanced(allow_hidden_flags=ALL_HIDDEN_REASONS) or result.sim_info.id in self._blacklist_sim_ids or result.sim_info.id in global_blacklist: results.remove(result) sorted_results = sorted(results, key=lambda x: x.score, reverse=True) if self._sim_filter.use_weighted_random: index = filters.tunable.TunableSimFilter.TOP_NUMBER_OF_SIMS_TO_LOOK_AT randomization_group = [(result.score, result.sim_info) for result in sorted_results[:index]] while index < len(sorted_results): while len(self._selected_sim_infos) < sims_to_spawn: random_choice = random.pop_weighted(randomization_group) randomization_group.append((sorted_results[index].score, sorted_results[index].sim_info)) logger.info('Sim ID matching request {0}', random_choice) self._selected_sim_infos.append(random_choice) index += 1 while True: while randomization_group and len(self._selected_sim_infos) < self._number_of_sims_to_find: random_choice = random.pop_weighted(randomization_group) logger.info('Sim ID matching request {0}', random_choice) self._selected_sim_infos.append(random_choice) else: for result in sorted_results: if len(self._selected_sim_infos) == sims_to_spawn: break logger.info('Sim ID matching request {0}', result.sim_info) self._selected_sim_infos.append(result.sim_info) return self._selected_sim_infos
def _select_sims_from_results(self, results, sims_to_spawn): self._filter_results = [] self._filter_results_info = [] global_blacklist = services.sim_filter_service().get_global_blacklist() for result in tuple(results): if not result.sim_info.is_instanced( allow_hidden_flags=ALL_HIDDEN_REASONS): if not result.sim_info.id in self._blacklist_sim_ids: if result.sim_info.id in global_blacklist: results.remove(result) results.remove(result) sorted_results = sorted(results, key=lambda x: x.score, reverse=True) if self._sim_filter.use_weighted_random: index = filters.tunable.TunableSimFilter.TOP_NUMBER_OF_SIMS_TO_LOOK_AT randomization_group = [(result.score, result) for result in sorted_results[:index]] while index < len(sorted_results): while len(self._filter_results) < sims_to_spawn: random_choice = random.pop_weighted(randomization_group) if index < len(sorted_results): randomization_group.append( (sorted_results[index].score, sorted_results[index])) index += 1 logger.info('Sim ID matching request {0}', random_choice) self._filter_results.append(random_choice) self._filter_results_info.append(random_choice.sim_info) index += 1 if len(self._filter_results) < sims_to_spawn: if randomization_group: while True: while randomization_group and len( self._filter_results ) < self._number_of_sims_to_find: random_choice = random.pop_weighted( randomization_group) logger.info('Sim ID matching request {0}', random_choice) self._filter_results.append(random_choice) self._filter_results_info.append( random_choice.sim_info) else: for result in sorted_results: if len(self._filter_results) == sims_to_spawn: break logger.info('Sim ID matching request {0}', result.sim_info) self._filter_results.append(result) self._filter_results_info.append(result.sim_info) if self._sim_gsi_logging_data is not None: for result in self._filter_results: sim_filter_handlers.archive_filter_request( result.sim_info, self._sim_gsi_logging_data, rejected=False, reason='Score > 0 and chosen for spawning') return self._filter_results
def on_state_activated(self, reader=None, preroll_time_override=None): super().on_state_activated(reader=reader, preroll_time_override=preroll_time_override) if reader is not None: self._contest_situation_ids = reader.read_uint64s( CONTEST_TOKENS, None) if self._contest_situation_ids is None: self._contest_situation_ids = [] situation_manager = services.get_zone_situation_manager() max_contests = self._number_of_contests.upper_bound min_contests = self._number_of_contests.lower_bound if max_contests is None: max_contests = len(self._possible_contests) else: max_contests = min(len(self._possible_contests), max_contests) if min_contests is None: min_contests = len(self._possible_contests) min_contests = min(min_contests, max_contests) contest_count = random.random.randint(min_contests, max_contests) possible_situations = [ (possible_contest.weight, possible_contest.situation) for possible_contest in self._possible_contests ] while contest_count: contest_count -= 1 chosen_situation = random.pop_weighted(possible_situations) guest_list = SituationGuestList(invite_only=True) self._contest_situation_ids.append( situation_manager.create_situation(chosen_situation, guest_list=guest_list, user_facing=False))
def _trigger_phone_call_gen(self, timeline): client = services.client_manager().get_first_client() if client is None: return client_household = client.household if client_household is None: return sims_to_check = [sim for sim in client_household.instanced_sims_gen()] random.shuffle(sims_to_check) for sim in sims_to_check: call_types = [] ask_to_come_over_phone_call = HouseholdManager.PHONE_CALL_INFO.ask_to_come_over(sim) call_types.append((ask_to_come_over_phone_call.weight, ask_to_come_over_phone_call)) chat_phone_call = HouseholdManager.PHONE_CALL_INFO.chat(sim) call_types.append((chat_phone_call.weight, chat_phone_call)) invite_over_phone_call = HouseholdManager.PHONE_CALL_INFO.invite_over(sim) call_types.append((invite_over_phone_call.weight, invite_over_phone_call)) while call_types: call_type = pop_weighted(call_types) if call_type.try_and_setup(): call_type.execute() self._phone_call_element = None return yield element_utils.run_child(timeline, element_utils.sleep_until_next_tick_element()) self._phone_call_element = None
def create_offspring_data(self): r = random.Random() r.seed(self._seed) offspring_count = pop_weighted( [(p.weight * p.modifiers.get_multiplier(SingleSimResolver(self._sim_info)), p.size) for p in self.MULTIPLE_OFFSPRING_CHANCES], random=r) offspring_count = min(self._sim_info.household.free_slot_count + 1, offspring_count) self._offspring_data = [] for offspring_index in range(offspring_count): if offspring_index and r.random( ) < self.MONOZYGOTIC_OFFSPRING_CHANCE: gender = self._offspring_data[offspring_index - 1].gender genetics = self._offspring_data[offspring_index - 1].genetics else: gender = Gender.MALE if r.random() < 0.5 else Gender.FEMALE genetics = r.randint(1, MAX_UINT32) last_name = SimSpawner.get_family_name_for_gender( self._sim_info.account, self._sim_info.last_name, gender == Gender.FEMALE) traits = self._select_traits_for_offspring(gender) self._offspring_data.append( PregnancyOffspringData(gender, genetics, last_name=last_name, traits=traits))
def score_and_schedule_nodes_gen(self, nodes_to_score, nodes_to_schedule, specific_time=None, time_modifier=TimeSpan.ZERO, timeline=None, gsi_data=None, **additional_drama_node_kwargs): active_household = services.active_household() if active_household is None: return self._update_cooldowns() sim_resolvers = tuple(SingleSimResolver(sim_info) for sim_info in active_household.sim_info_gen()) possible_nodes = [] chosen_node_types = set() for drama_node in nodes_to_score: if not self._is_node_on_cooldown(drama_node) or gsi_data is not None: gsi_data.rejected_nodes.append(GSIRejectedDramaNodeScoringData(drama_node, '{} is on cooldown.', drama_node)) for resolver in sim_resolvers: uid = id_generator.generate_object_id() drama_node_inst = drama_node(uid) result = drama_node_inst.setup(resolver, gsi_data=gsi_data, **additional_drama_node_kwargs) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) if not result: drama_node_inst.cleanup() else: score = drama_node_inst.score() if score == 0: if gsi_data is not None: gsi_data.rejected_nodes.append(GSIRejectedDramaNodeScoringData(drama_node, 'Scoring generated a score of 0.', score=score, receiver=drama_node_inst.get_receiver_sim_info(), sender=drama_node_inst.get_sender_sim_info())) drama_node_inst.cleanup() else: if gsi_data is not None: gsi_data.potential_nodes.append(GSIDramaNodeScoringData(drama_node, score, drama_node_inst.get_score_details(), drama_node_inst.get_receiver_sim_info(), drama_node_inst.get_sender_sim_info())) possible_nodes.append((score, drama_node_inst)) if not possible_nodes: return while nodes_to_schedule > 0: while possible_nodes: chosen_node = random.pop_weighted(possible_nodes) if type(chosen_node) in chosen_node_types: if gsi_data is not None: gsi_data.rejected_nodes.append(GSIRejectedDramaNodeScoringData(type(drama_node_inst), 'Could not schedule drama node because a drama node of this type was already scheduled.', score=chosen_node.score(), score_details=chosen_node.get_score_details(), receiver=chosen_node.get_receiver_sim_info(), sender=chosen_node.get_sender_sim_info())) chosen_node.cleanup() else: result = chosen_node.schedule(None, specific_time=specific_time, time_modifier=time_modifier) if timeline is not None: yield timeline.run_child(elements.SleepElement(date_and_time.TimeSpan(0))) if not result: if gsi_data is not None: gsi_data.rejected_nodes.append(GSIRejectedDramaNodeScoringData(type(chosen_node), 'Could not schedule drama node because there are no valid times.', score=chosen_node.score(), score_details=chosen_node.get_score_details(), receiver=chosen_node.get_receiver_sim_info(), sender=chosen_node.get_sender_sim_info())) chosen_node.cleanup() else: if gsi_data is not None: gsi_data.chosen_nodes.append(GSIDramaNodeScoringData(type(chosen_node), chosen_node.score(), chosen_node.get_score_details(), chosen_node.get_receiver_sim_info(), chosen_node.get_sender_sim_info())) self._scheduled_nodes[chosen_node.uid] = chosen_node if chosen_node.cooldown is not None and chosen_node.cooldown.cooldown_option == CooldownOption.ON_SCHEDULE: self.start_cooldown(type(chosen_node)) if is_drama_node_log_enabled(): log_drama_node_scoring(chosen_node, DramaNodeLogActions.SCHEDULED) nodes_to_schedule -= 1 chosen_node_types.add(type(chosen_node)) for (score, drama_node_inst) in possible_nodes: drama_node_inst.cleanup()
def get_jog_waypoint_constraints(cls, context): sim = context.sim if context.pick is not None: pick_position = context.pick.location pick_vector = pick_position - sim.position pick_vector /= pick_vector.magnitude() else: pick_vector = sim.forward zone = services.current_zone() active_lot = zone.lot lot_corners = active_lot.corners sim_poly = sims4.geometry.CompoundPolygon(sims4.geometry.Polygon([sim.position])) lot_poly = sims4.geometry.CompoundPolygon(sims4.geometry.Polygon([corner for corner in lot_corners])) intersection = lot_poly.intersect(sim_poly) sim_on_lot = len(intersection) >= 1 if sim_on_lot: spawn_point = zone.get_spawn_point(lot_id=active_lot.lot_id, sim_spawner_tags=SimInfoSpawnerTags.SIM_SPAWNER_TAGS) origin_position = spawn_point.center routing_surface = routing.SurfaceIdentifier(zone.id, 0, routing.SURFACETYPE_WORLD) except_lot_id = active_lot.lot_id else: origin_position = sim.position routing_surface = sim.routing_surface except_lot_id = None interaction_constraint = Circle(origin_position, cls.CONSTRAINT_RADIUS, routing_surface=routing_surface, los_reference_point=None) jog_waypoint_constraints = [] zone = services.current_zone() active_lot = zone.lot constraint_set = zone.get_spawn_points_constraint(except_lot_id=except_lot_id) constraints_weighted = [] min_score = sims4.math.MAX_FLOAT for constraint in constraint_set: spawn_point_vector = constraint.average_position - sim.position score = sims4.math.vector_dot_2d(pick_vector, spawn_point_vector) if score < min_score: min_score = score constraints_weighted.append((score, constraint)) constraints_weighted = [(score - min_score, constraint) for (score, constraint) in constraints_weighted] constraints_weighted = sorted(constraints_weighted, key=lambda i: i[0]) first_constraint = constraints_weighted[-1][1] del constraints_weighted[-1] first_constraint_circle = Circle(first_constraint.average_position, cls.CONSTRAINT_RADIUS, routing_surface=first_constraint.routing_surface) jog_waypoint_constraints.append(first_constraint_circle) last_waypoint_position = first_constraint.average_position for _ in range(cls.NUM_JOG_POINTS - 1): constraints_weighted_next = [] for (_, constraint) in constraints_weighted: average_position = constraint.average_position distance_last = (average_position - last_waypoint_position).magnitude_2d() distance_home = (average_position - origin_position).magnitude_2d() constraints_weighted_next.append((distance_last + distance_home, constraint)) next_constraint = pop_weighted(constraints_weighted_next) next_constraint_circle = Circle(next_constraint.average_position, cls.CONSTRAINT_RADIUS, routing_surface=next_constraint.routing_surface) jog_waypoint_constraints.append(next_constraint_circle) constraints_weighted = constraints_weighted_next last_waypoint_position = next_constraint.average_position jog_waypoint_constraints.append(interaction_constraint) return (interaction_constraint, jog_waypoint_constraints)
def try_place_object(self, obj, resolver, **kwargs): for strategy_group in self.placement_strategy_groups: strategies = [(entry.weight.get_multiplier(resolver), entry.placement_strategy) for entry in strategy_group] while strategies: strategy = pop_weighted(strategies) if strategy.try_place_object(obj, resolver, **kwargs): return True return False
def get_winners(self, contest): num_rewards = len(contest.festival_contest_tuning._win_rewards) scores = [(contest_score.score, contest_score) for contest_score in contest._scores] winners = [] while scores: if len(winners) < num_rewards: winner = random.pop_weighted(scores) winners.append(winner) return winners
def create_offspring_data(self): r = random.Random() r.seed(self._seed) if self._offspring_count_override is not None: offspring_count = self._offspring_count_override else: offspring_count = pop_weighted([ (p.weight * p.modifiers.get_multiplier(SingleSimResolver(self._sim_info)), p.size) for p in self.MULTIPLE_OFFSPRING_CHANCES ], random=r) offspring_count = min(self._sim_info.household.free_slot_count + 1, offspring_count) species = self._sim_info.species age = self._sim_info.get_birth_age() aging_data = AgingTuning.get_aging_data(species) num_personality_traits = aging_data.get_personality_trait_count(age) self._offspring_data = [] for offspring_index in range(offspring_count): if offspring_index and r.random( ) < self.MONOZYGOTIC_OFFSPRING_CHANCE: gender = self._offspring_data[offspring_index - 1].gender genetics = self._offspring_data[offspring_index - 1].genetics else: gender_chance_stat = self._sim_info.get_statistic( self.GENDER_CHANCE_STAT) if gender_chance_stat is None: gender_chance = 0.5 else: gender_chance = (gender_chance_stat.get_value() - gender_chance_stat.min_value) / ( gender_chance_stat.max_value - gender_chance_stat.min_value) gender = Gender.FEMALE if r.random( ) < gender_chance else Gender.MALE genetics = r.randint(1, MAX_UINT32) last_name = SimSpawner.get_last_name(self._sim_info.last_name, gender, species) offspring_data = PregnancyOffspringData(age, gender, species, genetics, last_name=last_name) (parent_a, parent_b) = self.get_parents() offspring_data.traits = self.select_traits_for_offspring( offspring_data, parent_a, parent_b, num_personality_traits, origin=self._origin) self._offspring_data.append(offspring_data)
def add_quirks(self, sim_info): trait_tracker = sim_info.trait_tracker r = random.Random(sim_info.sim_id) for quirk_set in self._quirk_sets: quirk_count = quirk_set.count(sim_info, r) quirk_count_current = sum(1 for entry in quirk_set.entries if sim_info.has_trait(entry.quirk_trait)) allowed_entries = [(entry.quirk_relative_weight, entry.quirk_trait) for entry in quirk_set.entries if trait_tracker.can_add_trait(entry.quirk_trait)] while allowed_entries: if quirk_count_current >= quirk_count: break quirk_trait = pop_weighted(allowed_entries, random=r) if sim_info.add_trait(quirk_trait): quirk_count_current += 1
def create_offspring_data(self): r = random.Random() r.seed(self._seed) offspring_count = pop_weighted([(p.weight*p.modifiers.get_multiplier(SingleSimResolver(self._sim_info)), p.size) for p in self.MULTIPLE_OFFSPRING_CHANCES], random=r) offspring_count = min(self._sim_info.household.free_slot_count + 1, offspring_count) self._offspring_data = [] for offspring_index in range(offspring_count): if offspring_index and r.random() < self.MONOZYGOTIC_OFFSPRING_CHANCE: gender = self._offspring_data[offspring_index - 1].gender genetics = self._offspring_data[offspring_index - 1].genetics else: gender = Gender.MALE if r.random() < 0.5 else Gender.FEMALE genetics = r.randint(1, MAX_UINT32) last_name = SimSpawner.get_family_name_for_gender(self._sim_info.account, self._sim_info.last_name, gender == Gender.FEMALE) traits = self._select_traits_for_offspring(gender) self._offspring_data.append(PregnancyOffspringData(gender, genetics, last_name=last_name, traits=traits))
def get_waypoint_constraints_gen(self, routing_agent, waypoint_count): zone = services.current_zone() constraint_set = zone.get_spawn_points_constraint(except_lot_id=self._except_lot_id, sim_spawner_tags=self.spawn_point_tags, generalize=True) routing_context = routing_agent.routing_component.pathplan_context source_handle = routing.connectivity.Handle(routing_agent.position, routing_agent.routing_surface) dest_handles = set() for constraint in constraint_set: handles = constraint.get_connectivity_handles(routing_agent) dest_handles.update(handles) connectivity = routing.test_connectivity_batch((source_handle,), dest_handles, routing_context=routing_context, compute_cost=True) vehicle_dest_handles = {dest for (_, dest, cost) in connectivity if sims4.math.almost_equal(cost, 0.0)} constraint_set = create_constraint_set([handle.constraint for handle in vehicle_dest_handles]) constraints_weighted = [] min_score = sims4.math.MAX_FLOAT for constraint in constraint_set: spawn_point_vector = constraint.average_position - self._sim.position score = sims4.math.vector_dot_2d(self._pick_vector, spawn_point_vector) min_score = score constraints_weighted.append((score, constraint)) constraints_weighted = [(score - min_score, constraint) for (score, constraint) in constraints_weighted] constraints_weighted = sorted(constraints_weighted, key=lambda i: i[0]) first_constraint = constraints_weighted[-1][1] del constraints_weighted[-1] first_constraint_circle = Circle(first_constraint.average_position, self.constraint_radius, routing_surface=first_constraint.routing_surface) jog_waypoint_constraints = [] jog_waypoint_constraints.append(first_constraint_circle) last_waypoint_position = first_constraint.average_position for _ in range(waypoint_count - 1): constraints_weighted_next = [] for (_, constraint) in constraints_weighted: average_position = constraint.average_position distance_last = (average_position - last_waypoint_position).magnitude_2d() distance_home = (average_position - self._origin_position).magnitude_2d() constraints_weighted_next.append((distance_last + distance_home, constraint)) break next_constraint = pop_weighted(constraints_weighted_next) next_constraint_circle = Circle(next_constraint.average_position, self.constraint_radius, routing_surface=next_constraint.routing_surface) jog_waypoint_constraints.append(next_constraint_circle) constraints_weighted = constraints_weighted_next break last_waypoint_position = next_constraint.average_position jog_waypoint_constraints = self.apply_water_constraint(jog_waypoint_constraints) yield from jog_waypoint_constraints yield self._start_constraint
def select_traits_for_offspring(cls, offspring_data, parent_a, parent_b, num_traits, origin=PregnancyOrigin.DEFAULT, random=random): traits = [] personality_trait_slots = num_traits def _add_trait_if_possible(selected_trait): nonlocal personality_trait_slots if selected_trait in traits: return False if any(t.is_conflicting(selected_trait) for t in traits): return False if selected_trait.is_personality_trait: if not personality_trait_slots: return False personality_trait_slots -= 1 traits.append(selected_trait) return True if origin in cls.PREGNANCY_ORIGIN_MODIFIERS: trait_entries = cls.PREGNANCY_ORIGIN_MODIFIERS[ origin].trait_entries for trait_entry in trait_entries: if random.random() >= trait_entry.chance: continue selected_trait = pop_weighted( [(t.weight, t.trait) for t in trait_entry.traits if t.trait.is_valid_trait(offspring_data)], random=random) if selected_trait is not None: _add_trait_if_possible(selected_trait) if parent_a is not None: if parent_b is not None: for inherited_trait_entries in parent_a.trait_tracker.get_inherited_traits( parent_b): selected_trait = pop_weighted( list(inherited_trait_entries), random=random) if selected_trait is not None: _add_trait_if_possible(selected_trait) if not personality_trait_slots: return traits personality_traits = get_possible_traits(offspring_data) random.shuffle(personality_traits) while True: current_trait = personality_traits.pop() if _add_trait_if_possible(current_trait): break if not personality_traits: return traits if not personality_trait_slots: return traits traits_a = set(parent_a.trait_tracker.personality_traits) traits_b = set(parent_b.trait_tracker.personality_traits) shared_parent_traits = list( traits_a.intersection(traits_b) - set(traits)) random.shuffle(shared_parent_traits) while personality_trait_slots: while shared_parent_traits: current_trait = shared_parent_traits.pop() if current_trait in personality_traits: personality_traits.remove(current_trait) did_add_trait = _add_trait_if_possible(current_trait) if did_add_trait: if not personality_trait_slots: return traits remaining_parent_traits = list( traits_a.symmetric_difference(traits_b) - set(traits)) random.shuffle(remaining_parent_traits) while personality_trait_slots: while remaining_parent_traits: current_trait = remaining_parent_traits.pop() if current_trait in personality_traits: personality_traits.remove(current_trait) did_add_trait = _add_trait_if_possible(current_trait) if did_add_trait: if not personality_trait_slots: return traits while personality_trait_slots: while personality_traits: current_trait = personality_traits.pop() _add_trait_if_possible(current_trait) return traits