def on_update(self): super().on_update() if not services.sim_spawner_service().batch_spawning_complete: return _ZoneSpinUpStateResult.WAITING client = services.client_manager().get_first_client() services.sim_info_manager().on_spawn_sim_for_zone_spin_up_completed( client) services.venue_service().get_zone_director( ).on_spawn_sim_for_zone_spin_up_completed() services.current_zone( ).venue_service.handle_active_lot_changing_edge_cases() services.get_zone_situation_manager( ).on_all_sims_spawned_during_zone_spin_up() club_service = services.get_club_service() if club_service is not None: club_service.on_finish_waiting_for_sim_spawner_service() else: current_zone_id = services.current_zone_id() household = services.active_household() if household.home_zone_id != current_zone_id: sim_info_manager = services.sim_info_manager() traveled_sims = sim_info_manager.get_traveled_to_zone_sim_infos( ) if len(traveled_sims) > 1: services.ensemble_service( ).create_travel_ensemble_if_neccessary(traveled_sims) services.ensemble_service().on_all_sims_spawned_during_zone_spin_up() return _ZoneSpinUpStateResult.DONE
def _do_behavior(self, *args, **kwargs): subject = self.interaction.get_participant(self.subject) if subject is None: logger.error( "DestroyEnsemble: Trying to destroy a non-existent Sim's ensemble." ) return services.ensemble_service().destroy_sims_ensemble( self.ensemble_type, subject)
def _do_behavior(self, *args, **kwargs): subject = self.interaction.get_participant(self.subject) if subject is None: logger.error( 'RemoveFromEnsemble: Trying to remove a non-existent Sim from an ensemble.' ) return services.ensemble_service().remove_sim_from_ensemble( self.ensemble_type, subject)
def _do_behavior(self, *args, **kwargs): actor = self.interaction.get_participant(self.actor) if actor is None: logger.error( "AddToEnsemble: Trying to add actor Sim who doesn't exist.") return target = self.interaction.get_participant(self.target) if target is None: logger.error( "AddToEnsemble: Trying to add target Sim who doesn't exist.") return services.ensemble_service().create_ensemble(self.ensemble_type, (actor, target))
def get_default_selection_data(actor_sim, filter_list): default_selection_data = [] club_service = services.get_club_service() ensemble_service = services.ensemble_service() gathering = None ensemble = None if club_service is not None: gathering = club_service.sims_to_gatherings_map.get(actor_sim) if ensemble_service is not None: ensembles = ensemble_service.get_all_ensembles_for_sim(actor_sim) familiar_tracker = actor_sim.sim_info.familiar_tracker active_familiar_sim_id = None if familiar_tracker is not None: active_familiar_sim_id = familiar_tracker.active_familiar_id_pet_id for item in filter_list: sim_info = item.sim_info if sim_info.sim_id == active_familiar_sim_id: default_selection_data.append((sim_info, True)) else: sim = sim_info.get_sim_instance() if sim is not None and (gathering and club_service.sims_to_gatherings_map.get(sim) is gathering or ensembles and any(sim in ensemble for ensemble in ensembles)): default_selection_data.append((sim_info, True)) else: default_selection_data.append((sim_info, False)) default_selection_data.sort(key=operator.itemgetter(1), reverse=True) return default_selection_data
def maybe_bring_group_along(self, **kwargs): if not self.should_rally: return anchor_object = self.target if anchor_object is not None: if anchor_object.is_part: anchor_object = anchor_object.part_owner if RallySource.SOCIAL_GROUP in self.rally_sources: main_group = self.sim.get_visible_group() if main_group: main_group.try_relocate_around_focus(self.sim, priority=self.priority) for sim in main_group: if sim is not self.sim: self._do_rally_behavior(sim, main_group.get_constraint(sim)) else: main_group = None if RallySource.ENSEMBLE in self.rally_sources: ensemble_sims = services.ensemble_service( ).get_ensemble_sims_for_rally(self.sim) if ensemble_sims: main_group_sims = set( main_group) if main_group else singletons.EMPTY_SET ensemble_sims -= main_group_sims for sim in ensemble_sims: if sim is not self.sim: self._do_rally_behavior(sim, None)
def should_rally(self): if self._from_rally_interaction is None: if RallySource.SOCIAL_GROUP in self.rally_sources: main_group = self.sim.get_visible_group() if main_group is not None and not main_group.is_solo: return True elif RallySource.ENSEMBLE in self.rally_sources: ensemble_sims = services.ensemble_service( ).get_ensemble_sims_for_rally(self.sim) if ensemble_sims: return True elif RallySource.ENSEMBLE in self.rally_sources: ensemble_sims = services.ensemble_service( ).get_ensemble_sims_for_rally(self.sim) if ensemble_sims: return True return False
def _on_update(self): with Context(self.layer) as layer: for ensemble in services.ensemble_service().get_all_ensembles(): color = pseudo_random_color(ensemble.guid) if ensemble.last_center_of_mass is None: continue layer.add_circle(ensemble.last_center_of_mass, radius=math.sqrt( ensemble.max_ensemble_radius), color=color) for sim in ensemble: layer.add_circle(sim.position, radius=0.3, color=color)
def _on_set_sim_job(self, sim, job_type): super()._on_set_sim_job(sim, job_type) if job_type is self.leader_job: for sim_info_id in sim.sim_info.squad_members: request = BouncerRequest( self, callback_data=_RequestUserData(), requested_sim_id=sim_info_id, job_type=self.squad_member_job, request_priority=BouncerRequestPriority.BACKGROUND_HIGH, user_facing=False, exclusivity=self.exclusivity) self.manager.bouncer.submit_request(request) else: if self._ensemble is None: services.ensemble_service().create_ensemble( self.ensemble_type, self._situation_sims.keys()) self._ensemble = services.ensemble_service( ).get_ensemble_for_sim(self.ensemble_type, sim) else: self._ensemble.add_sim_to_ensemble(sim) if job_type.job_uniform is None: self._fixup_sims_outfit(sim)
def sim_breaking_curfew(self, sim, target, interaction=None): if interaction is not None and self.interaction_blacklisted( interaction): return False if sim.sim_info.is_in_travel_group(): return False situation_manager = services.get_zone_situation_manager() sim_situations = situation_manager.get_situations_sim_is_in(sim) if any(situation.disallows_curfew_violation for situation in sim_situations): return False active_household = services.active_household() if active_household is None: return False home_zone_id = active_household.home_zone_id curfew_setting = self._zone_curfew_data.get(home_zone_id, CurfewService.UNSET) if sim.sim_info not in active_household: return False if curfew_setting is not CurfewService.UNSET: if sim.sim_info.is_young_adult_or_older: return False elif self.past_curfew(curfew_setting): if not services.current_zone_id() == home_zone_id: ensemble_service = services.ensemble_service() ensemble = ensemble_service.get_visible_ensemble_for_sim( sim) if ensemble is not None and any( sim.sim_info.is_young_adult_or_older and sim.sim_info in active_household for sim in ensemble): return False return True if target is not None and not target.is_in_inventory( ) and not services.active_lot().is_position_on_lot( target.position): return True elif target is None and not services.active_lot( ).is_position_on_lot(sim.position): return True return True if target is not None and not target.is_in_inventory( ) and not services.active_lot().is_position_on_lot( target.position): return True elif target is None and not services.active_lot( ).is_position_on_lot(sim.position): return True return False
def get_jig_definition(self): owner_sim = self.initiating_sim_info.get_sim_instance() ensemble_sims = services.ensemble_service( ).get_ensemble_sims_for_rally(owner_sim) sim_filter_service = services.sim_filter_service() filter_result_list = sim_filter_service.submit_filter( self.dance_member_job.filter, None, allow_yielding=False, sim_constraints=[sim.id for sim in ensemble_sims], requesting_sim_info=self.initiating_sim_info, gsi_source_fn=self.get_sim_filter_gsi_name) num_of_sims = len(filter_result_list) if num_of_sims not in self.jig_map: logger.error('Try to get jig for {} sims, which is not supported', num_of_sims) return self.jig_map.get(num_of_sims, None)
def create_auto_ensembles(self): ensemble_service = services.ensemble_service() rel_tracker = self.owner.relationship_tracker for (relationship_bit, ensemble_type) in self._rel_bit_ensembles.items(): target_sims = [] for target in rel_tracker.get_target_sim_infos(): if target is None: continue target_instance = target.get_sim_instance() if target_instance is None: continue if not rel_tracker.has_bit(target.sim_id, relationship_bit): continue target_sims.append(target_instance) if not target_sims: pass else: target_sim = max( target_sims, key=lambda s: ensemble_service.get_ensemble_for_sim( ensemble_type, s) is not None) ensemble_service.create_ensemble(ensemble_type, (self.owner, target_sim))
def build_relationship_bonuses(sim, sim_affinity_posture_scoring_data, sims_to_consider=None): bonuses = {} posture_graph = services.current_zone().posture_graph_service if not sims_to_consider: sims_to_consider = ( other_sim_info.get_sim_instance() for other_sim_info in services.sim_info_manager().objects if other_sim_info.is_instanced()) obj_to_cluster = {} clusters = list( services.social_group_cluster_service().get_clusters_gen()) for cluster in clusters: for obj in cluster.objects_gen(): obj_to_cluster[obj] = cluster relationship_tracker = sim.relationship_tracker most_important_ensemble = services.ensemble_service( ).get_most_important_ensemble_for_sim(sim) for other_sim in sims_to_consider: if other_sim is sim: continue if other_sim.posture.unconstrained: continue if other_sim.is_moving: continue if not other_sim.posture.allow_affinity: continue scores = [] zone_director = services.venue_service().get_zone_director() if sim_affinity_posture_scoring_data is not None: if not zone_director.disable_sim_affinity_posture_scoring(sim): tags = set() for si in other_sim.si_state: if si.sim_affinity_posture_scoring_data is not None: tags.update( si.sim_affinity_posture_scoring_data.my_tags) for scoring_strategy in sim_affinity_posture_scoring_data.my_scoring: match_tag = scoring_strategy.running_interaction_tag if match_tag == InteractionPostureAffinityTag.ALL: match = True else: match = (match_tag in tags) != scoring_strategy.negate_tag if not match: continue (affinity, message) = scoring_strategy.affinity_strategy( sim, other_sim) if not affinity: continue scores.append((affinity, message)) if most_important_ensemble is not None and most_important_ensemble.is_sim_in_ensemble( other_sim): scores.append((-PostureScoring.ENSEMBLE_BONUS, PostureScoring.ENSEMBLE_BONUS_MESSAGE)) elif not zone_director.disable_sim_affinity_posture_scoring( sim) and not relationship_tracker.has_bit( other_sim.sim_id, RelationshipGlobalTuning.HAS_MET_RELATIONSHIP_BIT): scores.append((PostureScoring.HAS_NOT_MET_PENALTY, PostureScoring.HAS_NOT_MET_COST_MESSAGE)) if not scores: pass else: other_sim_cluster = None other_sim_body_target = other_sim.posture_state.body_target if other_sim_body_target is not None: if other_sim_body_target.is_part: other_sim_body_target = other_sim_body_target.part_owner other_sim_cluster = obj_to_cluster.get( other_sim_body_target) other_sim_facing = sims4.math.yaw_quaternion_to_angle( other_sim.transform.orientation) distances = {} nodes_in_sight = posture_graph.nodes_matching_constraint_geometry( other_sim.los_constraint) for goal_node in nodes_in_sight: goal_body = goal_node[postures.posture_specs.BODY_INDEX] goal_body_target = goal_body[ postures.posture_specs.BODY_TARGET_INDEX] goal_posture_type = goal_body[ postures.posture_specs.BODY_POSTURE_TYPE_INDEX] if not goal_body_target is None: if goal_posture_type.mobile: continue distance = distances.get(goal_body_target) if distance is None: sim_facing = sims4.math.yaw_quaternion_to_angle( goal_body_target.transform.orientation) accum = accumulator.HarmonicMeanAccumulator() delta = other_sim.transform.translation - goal_body_target.transform.translation socials.geometry.score_facing( accum, sim_facing, other_sim_facing, delta) facing_score = accum.value() if facing_score <= 0: continue distance = (goal_body_target.position - other_sim.position).magnitude_2d() distance = max(distance, 1) distance /= facing_score distances[goal_body_target] = distance bonus = 0 all_messages = [] distance_modifier = RelationshipSimAffinityStrategy.DISTANCE_TO_IMPACT_CURVE.get( distance) for (affinity, message) in scores: affinity_weighted = affinity * distance_modifier bonus += affinity_weighted if not bonus: pass else: if goal_body_target.is_part: goal_object = goal_body_target.part_owner else: goal_object = goal_body_target if goal_object in obj_to_cluster: same_cluster = obj_to_cluster[ goal_object] is other_sim_cluster else: same_cluster = False if same_cluster: bonus *= PostureScoring.SAME_CLUSTER_SIM_MULTIPLIER current_bonus_info = bonuses.get(goal_body_target) if not current_bonus_info is None: if bonus < current_bonus_info[0]: formatted_message = '' bonuses[goal_body_target] = ( bonus, formatted_message) formatted_message = '' bonuses[goal_body_target] = (bonus, formatted_message) obj_to_cluster.clear() return bonuses
def remove_sim_from_ensemble(ensemble_type:TunableInstanceParam(sims4.resources.Types.ENSEMBLE), sim:RequiredTargetParam, _connection=None): services.ensemble_service().remove_sim_from_ensemble(ensemble_type, sim.get_target()) sims4.commands.output('Removed {} from ensembles.'.format(sim.get_target()), _connection)
def stop(self): services.ensemble_service().on_ensemble_center_of_mass_changed.remove( self._on_update)
def _start(self): services.ensemble_service().on_ensemble_center_of_mass_changed.append( self._on_update) self._on_update()
def create_ensemble(ensemble_type:TunableInstanceParam(sims4.resources.Types.ENSEMBLE), *sims:RequiredTargetParam, _connection=None): ensemble_sims = [sim.get_target() for sim in sims] services.ensemble_service().create_ensemble(ensemble_type, ensemble_sims) sims4.commands.output('Created Ensemble with sims {}'.format(ensemble_sims), _connection)