示例#1
0
class AmbientService(sims4.service_manager.Service):
    TEST_WALKBY_SITUATION = sims4.tuning.tunable.TunableReference(
        description=
        '\n                                            A walkby situation for testing.\n                                            ',
        manager=services.get_instance_manager(sims4.resources.Types.SITUATION))
    SOCIAL_AFFORDANCES = sims4.tuning.tunable.TunableList(
        description=
        '\n        When selected for a walkby social the sim runs one of the social\n        affordances in this list.\n        ',
        tunable=SocialSuperInteraction.TunableReference())
    SOCIAL_COOLDOWN = sims4.tuning.tunable.TunableSimMinute(
        description=
        '\n            The minimum amount of time from the end of one social\n            until the walkby sim can perform another social. If it is too small\n            sims may socialize, stop, then start socializing again.\n            ',
        default=60,
        minimum=30,
        maximum=480)
    SOCIAL_MAX_DURATION = sims4.tuning.tunable.TunableSimMinute(
        description=
        '\n            The maximum amount of time the sims can socialize.\n            ',
        default=60,
        minimum=1,
        maximum=180)
    SOCIAL_MAX_START_DISTANCE = sims4.tuning.geometric.TunableDistanceSquared(
        description=
        '\n            Walkby Sims must be less than this distance apart for a social\n            to be started.\n            ',
        default=10)
    SOCIAL_VIEW_CONE_ANGLE = sims4.tuning.tunable.TunableAngle(
        description=
        '\n            For 2 sims to be able to socialize at least one sim must be in the\n            view cone of the other. This tunable defines the view cone as an angle\n            in degrees centered straight out in front of the sim. 0 degrees would \n            make the sim blind, 360 degrees means the sim can see in all directions.\n            ',
        default=sims4.math.PI)
    SOCIAL_CHANCE_TO_START = sims4.tuning.tunable.TunablePercent(
        description=
        '\n            This is the percentage chance, per pair of properly positioned sims,\n            that a social will be started on an ambient service ping.\n\n            The number of pairs of sims is multiplied by this tunable to get the overall\n            chance of a social starting.\n            \n            For the purposes of these examples, we assume that the tuned value is 25%\n            \n            1 pair of sims -> 25%.\n            2 pairs of sims -> 50%\n            4 pairs of sims -> 100%.\n\n            ',
        default=100)

    def __init__(self):
        self._update_alarm_handle = None
        self._flavor_alarm_handle = None
        self._sources = []

    def stop(self):
        if self._update_alarm_handle is not None:
            alarms.cancel_alarm(self._update_alarm_handle)
            self._update_alarm_handle = None
        if self._flavor_alarm_handle is not None:
            alarms.cancel_alarm(self._flavor_alarm_handle)
            self._flavor_alarm_handle = None

    @classproperty
    def save_error_code(cls):
        return persistence_error_types.ErrorCodes.SERVICE_SAVE_FAILED_AMBIENT_SERVICE

    def save(self, open_street_data=None, **kwargs):
        if open_street_data is None:
            return
        open_street_data.ambient_service = gameplay_serialization.AmbientServiceData(
        )
        for source in self._sources:
            with ProtocolBufferRollback(
                    open_street_data.ambient_service.sources) as source_data:
                source.save(source_data)

    def begin_walkbys(self):
        self._sources.append(
            _AmbientSourceStreet(_AmbientSource.DEFAULT_PRIORITY_MULTIPLIER))
        self._sources.append(
            _AmbientSourceGhost(_AmbientSource.DEFAULT_PRIORITY_MULTIPLIER))
        for source in self._sources:
            source.begin_scheduled_walkbys()
        open_street_id = services.current_zone().open_street_id
        open_street_data = services.get_persistence_service(
        ).get_open_street_proto_buff(open_street_id)
        if open_street_data is not None:
            for source_data in open_street_data.ambient_service.sources:
                for source in self._sources:
                    if source.source_type == source_data.source_type:
                        source.load(source_data)
                        break
        self._update_alarm_handle = alarms.add_alarm(
            self,
            clock.interval_in_sim_minutes(5),
            self._update_alarm_callback,
            repeating=True,
            use_sleep_time=False)
        self._flavor_alarm_handle = alarms.add_alarm(
            self,
            clock.interval_in_sim_minutes(1),
            self._flavor_alarm_callback,
            repeating=True,
            use_sleep_time=False)

    def debug_update(self):
        return self._update(force_create=True)

    def start_specific_situation(self, situation_type):
        return self._sources[0].start_specific_situation(situation_type)

    def _update_alarm_callback(self, alarm_handle=None):
        client = services.client_manager().get_first_client()
        if client is None:
            return
        self._update()

    def _update(self, force_create=False):
        if not self._sources:
            return
        if gsi_handlers.ambient_handlers.archiver.enabled:
            gsi_description = self.get_gsi_description()
        else:
            gsi_description = None
        sources_and_priorities = [(source, source.get_priority())
                                  for source in self._sources]
        sources_and_priorities.sort(key=lambda source: source[1], reverse=True)
        situation_id = None
        source = sources_and_priorities[0][0]
        priority = sources_and_priorities[0][1]
        if priority > 0:
            situation_id = source.start_appropriate_situation()
        elif force_create:
            for (source, _) in sources_and_priorities:
                situation_id = source.start_appropriate_situation()
                if situation_id is not None:
                    break
        if gsi_handlers.ambient_handlers.archiver.enabled:
            situation = None
            if situation_id is not None:
                situation = services.current_zone().situation_manager.get(
                    situation_id)
            gsi_handlers.ambient_handlers.archive_ambient_data(
                gsi_description, created_situation=str(situation))
        return situation_id

    def _flavor_alarm_callback(self, _):
        if not self._sources:
            return
        social_available_sim_to_situation = {}
        flavor_available_sim_to_situation = {}
        for source in self._sources:
            for situation in source.get_running_situations():
                if isinstance(situation, WalkbyAmbientSituation):
                    sim = situation.get_sim_available_for_social()
                    if sim is not None:
                        social_available_sim_to_situation[sim] = situation
                    sim = situation.get_sim_available_for_walkby_flavor()
                    if sim is not None:
                        flavor_available_sim_to_situation[sim] = situation
        social_available_sims = list(social_available_sim_to_situation.keys())
        available_social_pairs = []
        for (actor_sim,
             target_sim) in itertools.combinations(social_available_sims, 2):
            if self._can_sims_start_social(actor_sim, target_sim):
                available_social_pairs.append((actor_sim, target_sim))
        if available_social_pairs and sims4.random.random_chance(
                len(available_social_pairs) * self.SOCIAL_CHANCE_TO_START *
                100):
            (actor_sim, target_sim) = available_social_pairs[random.randint(
                0,
                len(available_social_pairs) - 1)]
            social_available_sim_to_situation[actor_sim].start_social(
                social_available_sim_to_situation[target_sim])
            flavor_available_sim_to_situation.pop(actor_sim, None)
            flavor_available_sim_to_situation.pop(target_sim, None)
        for situation in flavor_available_sim_to_situation.values():
            if situation.random_chance_to_start_flavor_interaction():
                situation.start_flavor_interaction()
                break

    def _sim_forward_to_sim_dot(self, sim_one, sim_two):
        one_to_two = sim_two.position - sim_one.position
        one_to_two.y = 0
        if sims4.math.vector3_almost_equal(one_to_two,
                                           sims4.math.Vector3.ZERO()):
            return 1
        one_to_two = sims4.math.vector_normalize(one_to_two)
        one_to_two_dot = sims4.math.vector_dot_2d(
            sims4.math.vector_flatten(sim_one.forward), one_to_two)
        return one_to_two_dot

    def _can_sims_start_social(self, actor_sim, target_sim):
        distance_squared = (actor_sim.position -
                            target_sim.position).magnitude_squared()
        if distance_squared > self.SOCIAL_MAX_START_DISTANCE:
            return False
        cone_dot = math.cos(self.SOCIAL_VIEW_CONE_ANGLE * 0.5)
        actor_to_target_dot = self._sim_forward_to_sim_dot(
            actor_sim, target_sim)
        if actor_to_target_dot <= cone_dot:
            target_to_actor_dot = self._sim_forward_to_sim_dot(
                target_sim, actor_sim)
            if target_to_actor_dot <= cone_dot:
                return False
        if terrain.is_position_in_street(actor_sim.position):
            return False
        if terrain.is_position_in_street(target_sim.position):
            return False
        else:
            middle_position = (actor_sim.position + target_sim.position) * 0.5
            if terrain.is_position_in_street(middle_position):
                return False
        return True

    def get_gsi_description(self):
        if not self._sources:
            return ''
        description = self._sources[0].get_gsi_description()
        for source in self._sources[1:]:
            description = description + '   ' + source.get_gsi_description()
        return description
示例#2
0
 def _tunable_tests_enabled():
     return SocialSuperInteraction._tunable_tests_enabled()
示例#3
0
    class _ClubPickerActionChallenge(HasTunableSingletonFactory,
                                     AutoFactoryInit):
        FACTORY_TUNABLES = {
            'challenge_game':
            GameRules.TunableReference(
                description=
                '\n                The game that the club is being challenged at. This is used to\n                determine how many Sims are required, per team.\n                '
            ),
            'challenge_social_interaction':
            SocialSuperInteraction.TunableReference(
                description=
                '\n                Specify an interaction that the challenging Sim runs on a Sim in\n                the challenged club (usually the leader). Once this interaction\n                completes, the challenge executes.\n                '
            ),
            'challenge_interaction':
            SuperInteraction.TunableReference(
                description=
                '\n                The interaction to push on the Sims being challenged.\n                '
            )
        }

        def on_choice_selected(self, interaction, picked_items, **kwargs):
            club_service = services.get_club_service()
            if club_service is None:
                return
            actor_club_gathering = club_service.sims_to_gatherings_map.get(
                interaction.sim)
            if actor_club_gathering is None:
                return

            def _on_challenge_social_interaction_finished(
                    challenge_social_interaction):
                if not challenge_social_interaction.is_finishing_naturally:
                    return
                minimum_players_per_team = math.ceil(
                    self.challenge_game.players_per_game.lower_bound /
                    self.challenge_game.teams_per_game.lower_bound)
                maximum_players_per_team = math.floor(
                    self.challenge_game.players_per_game.upper_bound /
                    self.challenge_game.teams_per_game.upper_bound)
                teams = []
                for (_, club) in zip(
                        range(self.challenge_game.teams_per_game.upper_bound),
                        itertools.chain(
                            (actor_club_gathering.associated_club, ),
                            picked_items)):
                    club_gathering = club_service.clubs_to_gatherings_map.get(
                        club)
                    if club_gathering is None:
                        continue
                    club_team = set()
                    challenger_sims = (
                        interaction.sim,
                    ) if actor_club_gathering.associated_club is club else ()
                    for club_member in itertools.chain(
                            challenger_sims,
                            sorted(club_gathering.all_sims_in_situation_gen(),
                                   key=lambda sim: sim.sim_info is not club.
                                   leader)):
                        club_team.add(club_member)
                        if len(club_team) >= maximum_players_per_team:
                            break
                    if len(club_team) >= minimum_players_per_team:
                        teams.append(club_team)
                if len(teams) < self.challenge_game.teams_per_game.lower_bound:
                    return
                all_sims = tuple(itertools.chain.from_iterable(teams))
                game_transition_destination_node_validator = GameTransitionDestinationNodeValidator(
                    self.challenge_game, teams=teams)
                for sim in all_sims:
                    context = challenge_social_interaction.context.clone_for_sim(
                        sim,
                        group_id=challenge_social_interaction.group_id,
                        source_interaction_id=challenge_social_interaction.id,
                        source_interaction_sim_id=challenge_social_interaction.
                        sim.sim_id,
                        insert_strategy=QueueInsertStrategy.NEXT)
                    sim.push_super_affordance(
                        self.challenge_interaction,
                        interaction.target,
                        context,
                        game_transition_destination_node_validator=
                        game_transition_destination_node_validator)

            for club in picked_items:
                club_gathering = club_service.clubs_to_gatherings_map.get(club)
                if club_gathering is None:
                    continue
                for club_member in sorted(
                        club_gathering.all_sims_in_situation_gen(),
                        key=lambda sim: sim.sim_info is not club.leader):
                    context = interaction.context.clone_from_immediate_context(
                        interaction)
                    execute_result = interaction.sim.push_super_affordance(
                        self.challenge_social_interaction, club_member,
                        context)
                    if execute_result:
                        challenge_social_interaction = execute_result.interaction
                        challenge_social_interaction.register_on_finishing_callback(
                            _on_challenge_social_interaction_finished)
                        break