Ejemplo n.º 1
0
class TelemetryTuning:
    __qualname__ = 'TelemetryTuning'
    BUFF_ALARM_TIME = TunableRange(
        description=
        "\n        Integer value in sim minutes in which the buff alarm will trigger to \n        send a telemetry report of current active buff's on the household sims.\n        ",
        tunable_type=int,
        minimum=1,
        default=60)
    EMOTION_REL_ALARM_TIME = TunableRange(
        description=
        '\n        Integer value in sim minutes in which the emotion and relationship \n        alarm will trigger to send a telemetry report of the emotion and \n        relationship status of the household sims.\n        ',
        tunable_type=int,
        minimum=1,
        default=60)
    HOOK_ACTIONS = TunableList(
        description=
        '\n        List of hook actions that we want to drop or collect to create rules \n        to disable them from triggering.\n        ',
        tunable=TunableTuple(
            description='\n            Hook actions.\n            ',
            module_tag=Tunable(
                description=
                "\n                Module identifier of the hook where the action should be \n                applied.\n                Can be empty if we want to apply an action by only group or \n                hook tag. \n                e.g. 'GAME'.  \n                ",
                tunable_type=str,
                default=''),
            group_tag=Tunable(
                description=
                "\n                Group identifier of the hook where the action should be \n                applied.\n                Can be empty if we want to apply an action by only module or \n                hook tag.\n                e.g. 'WHIM'\n                ",
                tunable_type=str,
                default=''),
            hook_tag=Tunable(
                description=
                "\n                Tag identifier of the hook where the action should be \n                applied.\n                Can be empty if we want to apply an action by only module or \n                group tag.\n                e.g. 'WADD'\n                ",
                tunable_type=str,
                default=''),
            priority=Tunable(
                description=
                "\n                Priority for this rule to apply.  The rules are sorted in \n                priority order (lowest priority first).  The the first rule \n                that matches a hook causes the hook to be blocked or collected, \n                depending on the value of action. \n                e.g. We can have an action to COLLECT hook {GAME, WHIM, WADD} \n                with priority 0, and an action to DROP hooks with module 'GAME'\n                {GAME, '', ''} with priority 1, this means the collected hook\n                action will have more importance than the rule to drop all \n                GAME hooks.                \n                ",
                tunable_type=int,
                default=0),
            action=TunableEnumEntry(
                description=
                '\n                Action to take for the specified tags. \n                COLLECT to enable the hook.\n                DROP to disable the hook.\n                ',
                tunable_type=RuleAction,
                default=RuleAction.DROP)))

    @classmethod
    def filter_tunable_hooks(cls):
        for hook in TelemetryTuning.HOOK_ACTIONS:
            module_tag = hook.module_tag
            group_tag = hook.group_tag
            hook_tag = hook.hook_tag
            if module_tag == '':
                module_tag = None
            if group_tag == '':
                group_tag = None
            if hook_tag == '':
                hook_tag = None
            sims4.telemetry.add_filter_rule(hook.priority, module_tag,
                                            group_tag, hook_tag, None,
                                            hook.action)
Ejemplo n.º 2
0
 class _AwarenessChannelOptions(HasTunableSingletonFactory,
                                AutoFactoryInit):
     FACTORY_TUNABLES = {
         'gate':
         TunableRange(
             description=
             "\n                Any individual value lower than this gate is treated as 0. This\n                is essentially a noise filter: it prevents Sims from\n                overreacting to a large stimulus made up of very small stimuli.\n                \n                For example, imagine air conditioners producing very little\n                noise. If there were many air conditioners, a Sim might react.\n                Instead, if the noise level is below this value, the scores are\n                effectively discarded and don't contribute to the overall score.\n                ",
             tunable_type=float,
             default=0,
             minimum=0),
         'gain':
         TunableRange(
             description=
             "\n                A multiplier to apply to the awareness score. This allows Sims\n                to be more reactive than other Sims for the same stimulus.\n                \n                For example, you can tune a cat with extra-good hearing to\n                multiply the Audio Volume channel, so they'll react to noises\n                that are softer.\n                ",
             tunable_type=float,
             default=1,
             minimum=0),
         'threshold':
         TunableRange(
             description=
             '\n                A value below which Sims do not react to stimuli for this\n                channel. This allows different Sims to have different\n                tolerances.\n                \n                This can be used to dampen a Sim\'s awareness. For example, a\n                "Chill" cat might have this value set higher for the Proximity\n                channel, so that Sims close to it don\'t produce as much of a\n                reaction as other cats.\n                ',
             tunable_type=float,
             default=0.5,
             minimum=0)
     }
Ejemplo n.º 3
0
 def __init__(self, **kwargs):
     super().__init__(
         none=TunableRange(int,
                           5,
                           minimum=0,
                           description='Relative chance of no puddle.'),
         small=TunableRange(int,
                            5,
                            minimum=0,
                            description='Relative chance of small puddle.'),
         medium=TunableRange(
             int,
             0,
             minimum=0,
             description='Relative chance of medium puddle.'),
         large=TunableRange(int,
                            0,
                            minimum=0,
                            description='Relative chance of large puddle.'),
         liquid=TunableEnumEntry(
             description=
             '\n                The liquid of the puddle that will be generated.\n                ',
             tunable_type=PuddleLiquid,
             default=PuddleLiquid.WATER),
         **kwargs)
class NeighborhoodPopulationService(Service):
    __qualname__ = 'NeighborhoodPopulationService'
    REGION_TO_HOUSEHOLD_POPULATION_DATA = TunableMapping(description='\n        Mapping of Region Description ID to household population data.  This is\n        used to fill households for the different type of regions.\n        ', key_name='Region Description', key_type=TunableRegionDescription(), value_name='Household Population Data', value_type=HouseholdPopulationData.TunableFactory())
    HOMELESS_HOUSEHOLD_TEMPLATES = TunableList(description='\n        A List of household templates that will be considered for homelesss\n        households.\n        ', tunable=TunableHouseholdTemplateWeightTuple())
    NUM_BEDS_TO_IDEAL_HOUSEHOLD_CURVE = TunableMapping(description='\n        Based on the number of beds and the number of sims in the household, a\n        multiplier will be applied to the household to determine if household\n        will be selected and added to zone.\n        ', key_name='Num Beds', key_type=Tunable(tunable_type=int, default=1), value_name='Ideal Household Curve', value_type=TunableCurve(x_axis_name='num_sim_in_household', y_axis_name='bonus_multiplier'))
    KID_TO_KID_BED_MULTIPLIER = TunableRange(description='\n        When trying to populate a lot if lot has a kids bed and household has a\n        kid in it.  This multiplier will be applied to the weight of household\n        when selecting household to move in.\n        ', tunable_type=float, default=1, minimum=1)
    SIGNIFICANT_OTHER_MULTIPLIER = TunableRange(description='\n        When trying to populate a lot and if lot has a double bed and household\n        contains a pair of sims that are considered significant other.  This\n        multiplier will be applied to the weight of household when selecting\n        household to move in.\n        ', tunable_type=float, default=1, minimum=1)

    def __init__(self):
        self._requests = []
        self._processing_element_handle = None

    def _process_population_request_gen(self, timeline):
        while self._requests:
            request = self._requests.pop(0)
            try:
                yield request.process_request_gen(timeline)
                request.process_completed(True)
            except GeneratorExit:
                raise
            except BaseException:
                request.process_completed(False)
                logger.exception('Exception raised while processing creating npc households')
            while self._requests:
                yield element_utils.run_child(timeline, element_utils.sleep_until_next_tick_element())
                continue
        self._processing_element_handle = None

    def add_population_request(self, num_to_fill, neighborhood_id, completion_callback, available_zone_ids, try_existing_households):
        account = self._get_account()
        if account is None:
            return False
        request = _FillZonePopulationRequest(account, num_to_fill, neighborhood_id, completion_callback, available_zone_ids=available_zone_ids, try_existing_households=try_existing_households)
        self._add_request(request)
        return True

    def add_homeless_household_request(self, num_to_fill, completion_callback):
        account = self._get_account()
        if account is None:
            return False
        request = _CreateHomelessHouseholdRequest(account, num_to_fill, None, completion_callback)
        self._add_request(request)
        return True

    def _get_account(self):
        client = services.client_manager().get_first_client()
        if client.account is not None or client.household is not None:
            return client.account

    @property
    def is_processing_requests(self):
        return self._processing_element_handle or len(self._requests) > 0

    def _add_request(self, request):
        self._requests.append(request)
        if self._processing_element_handle is None:
            timeline = services.time_service().sim_timeline
            element = elements.GeneratorElement(self._process_population_request_gen)
            self._processing_element_handle = timeline.schedule(element)
Ejemplo n.º 5
0
class _WaypointGeneratorObjectPoints(_WaypointGeneratorBase):
    FACTORY_TUNABLES = {
        'object_constraint_radius':
        TunableRange(
            description=
            '\n            The radius, in meters, of the generated constraint around the \n            target object where the waypoints will be generated.\n            ',
            tunable_type=float,
            default=3,
            minimum=0),
        'waypoint_constraint_radius':
        TunableRange(
            description=
            '\n            The radius, in meters, for each generated waypoint inside the \n            object constraint radius for the Sim to route to.\n            ',
            tunable_type=float,
            default=1,
            minimum=1)
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if self._target is None:
            self._start_constraint = Nowhere(
                'Trying to generate a waypoint constraint without a target.')
            self._los_reference_point = None
        else:
            self._los_reference_point = self._target.position
            if self._target.is_terrain:
                self._los_reference_point = None
            self._start_constraint = Circle(
                self._target.position,
                self.object_constraint_radius,
                routing_surface=self._routing_surface,
                los_reference_point=self._los_reference_point)
            self._start_constraint = self._start_constraint.intersect(
                self.get_water_constraint())

    def get_start_constraint(self):
        return self._start_constraint

    def get_waypoint_constraints_gen(self, routing_agent, waypoint_count):
        polygon = self._start_constraint.geometry.polygon
        object_waypoint_constraints = []
        object_waypoint = Circle(self._target.position,
                                 self.waypoint_constraint_radius,
                                 routing_surface=self._target.routing_surface,
                                 los_reference_point=self._los_reference_point)
        object_waypoint_constraints.append(object_waypoint)
        for position in random_uniform_points_in_compound_polygon(
                polygon, num=waypoint_count):
            object_waypoint_constraints.append(
                Circle(position,
                       self.waypoint_constraint_radius,
                       routing_surface=self._start_constraint.routing_surface,
                       los_reference_point=self._los_reference_point))
            object_waypoint_constraints.append(object_waypoint)
        object_waypoint_constraints = self.apply_water_constraint(
            object_waypoint_constraints)
        yield from object_waypoint_constraints
Ejemplo n.º 6
0
class AdvertisingConfiguration(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'default_advertising_type':
        OptionalTunable(
            description=
            '\n            Set the default advertising type for the initial business.  This\n            should map to a key in advertising_data_map.\n            ',
            tunable=TunableEnumEntry(
                description=
                '\n                The Advertising Type .\n                ',
                tunable_type=BusinessAdvertisingType,
                default=BusinessAdvertisingType.INVALID,
                invalid_enums=(BusinessAdvertisingType.INVALID, )),
            disabled_name='No_Default_Advertisement_Type'),
        'advertising_data_map':
        TunableMapping(
            description=
            '\n            The mapping between advertising type and the data for that type.\n            ',
            key_type=TunableEnumEntry(
                description=
                '\n                The Advertising Type .\n                ',
                tunable_type=BusinessAdvertisingType,
                default=BusinessAdvertisingType.INVALID,
                invalid_enums=(BusinessAdvertisingType.INVALID, )),
            value_type=TunableTuple(
                description=
                '\n                Data associated with this advertising type.\n                ',
                cost_per_hour=TunableRange(
                    description=
                    '\n                    How much, per hour, it costs to use this advertising type.\n                    ',
                    tunable_type=int,
                    default=10,
                    minimum=0),
                customer_count_multiplier=TunableRange(
                    description=
                    '\n                    This amount is multiplied by the ideal customer count for owned\n                    restaurants.\n                    ',
                    tunable_type=float,
                    default=0.8,
                    minimum=0)))
    }

    def get_advertising_cost_per_hour(self, advertising_type):
        config = self.advertising_data_map.get(advertising_type, None)
        if config is not None:
            return config.cost_per_hour
        logger.error(
            'There is no cost per hour tuned for advertising type {}'.format(
                advertising_type))
        return 0.0

    def get_customer_count_multiplier(self, advertising_type):
        config = self.advertising_data_map.get(advertising_type, None)
        if config is not None:
            return config.customer_count_multiplier
        logger.error(
            'There is no customer count multiplier tuned for advertising type {}'
            .format(advertising_type))
        return 1.0
Ejemplo n.º 7
0
class SpellbookTuning:
    FRONT_PAGE_DATA = TunableTuple(description='\n        UI-specific data used to display front page.\n        ', title=TunableLocalizedStringFactory(description='\n            The title to use on the front page of the spellbook.\n            '), icon=OptionalTunable(description='\n            Image displayed on front page of spellbook.\n            If unset, image is not shown.\n            ', tunable=TunableIconAllPacks()), page_description=OptionalTunable(description='\n            Description used for this page in the spellbook.\n            If unset, description is not shown.\n            ', tunable=TunableLocalizedString()))
    CATEGORY_LIST_DATA = TunableTuple(description='\n        UI-specific data used to display second page of the spellbook.\n        ', title=TunableLocalizedStringFactory(description='\n            The title to use on the category list of the spellbook.\n            '), icon=OptionalTunable(description='\n            Icon used on the category list page of the spellbook.\n            ', tunable=TunableIconAllPacks()), page_description=OptionalTunable(description='\n            Description used for this page in the spellbook.\n            If unset, description is not shown.\n            ', tunable=TunableLocalizedString()))
    CATEGORY_DATAS = TunableList(description='\n        A list of a spellbook category data.\n        ', tunable=SpellbookCategoryData.TunableFactory(), tuning_group=GroupNames.UI)
    POTION_DISPLAY_DATA = TunableMapping(description="\n        A mapping of a potion's recipe to it's spellbook display data. \n        ", key_type=TunableReference(description="\n            The potion's recipe.\n            ", manager=services.get_instance_manager(Types.RECIPE), class_restrictions=('Recipe',), pack_safe=True), value_type=SpellbookRecipeData.TunableFactory(), tuning_group=GroupNames.UI)
    INGREDIENTS_LABEL = TunableLocalizedString(description='\n        Text used to display ingredients label for a spell or potion.\n        \n        e.g. "Ingredients:"\n        ', tuning_group=GroupNames.UI)
    PROGRESS_LABEL = TunableLocalizedString(description='\n        Text used to display field name for progress into a specific\n        category.\n        \n        e.g. "Learned:"\n        ', tuning_group=GroupNames.UI)
    PROGRESS_TEXT_FORMAT = TunableLocalizedStringFactory(description='\n        Text used to display the progress towards completing a specific\n        category.  Takes current items learned and and total available.\n\n        e.g. "{0.Number}/{1.Number}"\n        ', tuning_group=GroupNames.UI)
    CATEGORY_FRONT_PAGE_ENTRY_COUNT = TunableRange(description=',\n        Number of entries allotted for the front page of a category section.\n        ', tunable_type=int, minimum=0, tuning_group=GroupNames.UI, default=2)
    CATEGORY_ENTRY_COUNT = TunableRange(description=',\n        Number of entries allotted for the subsequent pages of a category section.\n        ', tunable_type=int, minimum=1, tuning_group=GroupNames.UI, default=4)
    INGREDIENT_FORMAT = TunableLocalizedStringFactory(description='\n        The format used for ingredients in the spellbook.\n        First parameter will be name of ingredient, second will be quantity required.\n        e.g. {0.String}({1.Number}) = "Frog(1)"\n        ', tuning_group=GroupNames.UI)
Ejemplo n.º 8
0
class SpawnerInitializer:
    SPAWN_FREQUENCY = Tunable(
        description=
        '\n        This is the frequency at which the spawner components spawn the\n        individual objects for the first time you are playing in the zone.\n        Please talk with a GPE about performance concerns if you tune this\n        value.\n        ',
        tunable_type=int,
        default=5)
    SPAWN_DELAYED_START = TunableRange(
        description=
        '\n        This is the minimum amount of sim minutes we wait before we start\n        spawning objects for the first time in the zone at SPAWN_FREQUENCY. We\n        pick a random time between the start and end delayed time.\n        ',
        tunable_type=int,
        minimum=0,
        default=15)
    SPAWN_DELAYED_END = TunableRange(
        description=
        '\n        This is the maximum amount of sim minutes we wait before we start\n        spawning objects for the first time in the zone at SPAWN_FREQUENCY. We\n        pick a random time between the start and end delayed time.\n        ',
        tunable_type=int,
        minimum=0,
        default=60)

    @classmethod
    def create(cls, zone_id):
        global SpawnerInitializerSingleton
        if SpawnerInitializerSingleton is not None and SpawnerInitializerSingleton.zone_id != zone_id:
            SpawnerInitializerSingleton.destroy()
        if SpawnerInitializerSingleton is None:
            SpawnerInitializerSingleton = SpawnerInitializer(zone_id)

    @classmethod
    def destroy(cls):
        global SpawnerInitializerSingleton
        SpawnerInitializerSingleton = None

    def __init__(self, zone_id):
        self._zone_id = zone_id

    @property
    def zone_id(self):
        return self._zone_id

    def spawner_spawn_objects_post_nav_mesh_load(self, zone_id):
        if zone_id == self._zone_id:
            for obj in services.object_manager(
                    self._zone_id).get_all_objects_with_component_gen(
                        SPAWNER_COMPONENT):
                obj.spawner_component.initialize_spawning()
        else:
            logger.info(
                'Mismatched zone id in Spawner initialization. Fence Zone id: {}. Registered Zone id: {}',
                zone_id, self._zone_id)
            self.destroy()
Ejemplo n.º 9
0
class WalkstyleBehaviorOverride(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'walkstyle_behavior_priority':
        TunableEnumEntry(
            description=
            '\n            Define the priority of this override relative to other overrides.\n            This is meaningful for the non-additive properties of this override.\n            ',
            tunable_type=WalkstyleBehaviorOverridePriority,
            default=WalkstyleBehaviorOverridePriority.DEFAULT),
        'run_required_total_distance':
        _get_tunable_override(tunable=TunableRange(
            description=
            '\n                For an entire route, the minimum distance required for Sim to\n                run.\n                ',
            tunable_type=float,
            minimum=0,
            default=20)),
        'run_required_segment_distance':
        _get_tunable_override(tunable=TunableRange(
            description=
            '\n                For a specific route segment, the minimum distance required for\n                the Sim to run.\n                ',
            tunable_type=float,
            minimum=0,
            default=10)),
        'run_walkstyle':
        _get_tunable_override(tunable=TunableWalkstyle(
            description=
            '\n                Override the walkstyle to use when this Sim is supposed to be running.\n                '
        )),
        'short_walkstyle':
        _get_tunable_override(tunable=TunableWalkstyle(
            description=
            '\n                Override walkstyle used when Sims are routing over a short distance.\n                '
        )),
        'wading_walkstyle':
        _get_tunable_override(tunable=TunableWalkstyle(
            description=
            '\n                Override walkstyle used when Sims are walking through the water.\n                '
        )),
        'additional_run_flags':
        TunableEnumFlags(
            description=
            '\n            Define where the Sim is allowed to run.\n            \n            NOTE: This is *additive*, meaning the resulting run flags for a Sim\n            are defined by the default tuning plus all overrides. However,\n            removed_run_flags is applied last.\n            ',
            enum_type=WalkStyleRunAllowedFlags,
            allow_no_flags=True),
        'removed_run_flags':
        TunableEnumFlags(
            description=
            '\n            Modify a Sim\'s ability to run.\n            \n            NOTE: This is *additive* with respect to all overrides, and is\n            applied to the combination of the default tuning plus\n            additional_run_flags from all overrides.\n            \n            e.g.: The default behavior for a human is to exclusively run\n            outdoors. A hypothetical "excitable" trait might add the ability to\n            run indoors (meaning the total result is indoors+outdoors). However,\n            the "pregnant" trait might remove the ability to run (both outdoors\n            and indoors), effectively preventing the Sim from running at all.\n            ',
            enum_type=WalkStyleRunAllowedFlags,
            allow_no_flags=True)
    }
Ejemplo n.º 10
0
class EmergencyFrequency(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'max_emergency_situations_per_shift':
        TunableRange(
            description=
            '\n            The maximum number of times during a shift that an emergency\n            situation can be created/started.\n            ',
            tunable_type=int,
            default=1,
            minimum=0),
        'inital_lockout_in_sim_minutes':
        TunableSimMinute(
            description=
            '\n            The time, in Sim minutes, that pass at the beginning of a shift\n            before the first check for creating/starting an emergency happens.\n            ',
            default=60),
        'cool_down_in_sim_minutes':
        TunableSimMinute(
            description=
            '\n            How often a check for whether or not to create/start an emergency\n            happens.\n            ',
            default=60),
        'percent_chance_of_emergency':
        TunablePercent(
            description=
            '\n            The percentage chance that on any given check an emergency is to\n            to be created/started.\n            ',
            default=30),
        'weighted_situations':
        TunableList(
            description=
            '\n            A weighted list of situations to be used as emergencies. When a\n            check passes to create/start an emergency, this is the list\n            of emergency situations that will be chosen from.\n            ',
            tunable=TunableTuple(situation=Situation.TunableReference(),
                                 weight=Tunable(tunable_type=int, default=1)))
    }
Ejemplo n.º 11
0
class TunableRewardWhimBucks(AutoFactoryInit, TunableRewardBase):
    FACTORY_TUNABLES = {
        'whim_bucks':
        TunableRange(
            description=
            '\n            The number of whim bucks to give.\n            ',
            tunable_type=int,
            default=1,
            minimum=1)
    }

    @constproperty
    def reward_type():
        return RewardType.WHIM_BUCKS

    def open_reward(self,
                    sim_info,
                    reward_destination=RewardDestination.HOUSEHOLD,
                    **kwargs):
        if reward_destination == RewardDestination.HOUSEHOLD:
            household = sim_info.household
            for sim_info in household.sim_info_gen():
                sim_info.add_whim_bucks(self.whim_bucks, SetWhimBucks.COMMAND)
        elif reward_destination == RewardDestination.SIM:
            sim_info.add_whim_bucks(self.whim_bucks, SetWhimBucks.COMMAND)
        else:
            logger.error(
                'Attempting to open a RewardWhimBucks with an invalid destination: {}. Reward whim bucks can only be given to households or Sims.',
                reward_destination)
Ejemplo n.º 12
0
class _TextInputLengthFixed(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'min_length':
        OptionalTunable(
            description=
            "\n             If enabled, specify the minimum length of input text the player has\n             to enter before he/she can hit the 'OK' button.\n             ",
            tunable=TunableTuple(
                length=TunableRange(
                    description=
                    '\n                     Minimum amount of characters the user must enter in to the\n                     text box before he/she can click on the OK button.\n                     ',
                    tunable_type=int,
                    minimum=1,
                    default=1),
                tooltip=OptionalTunable(
                    description=
                    '\n                     If enabled, allows specification of a tooltip to display if\n                     the user has entered text length less than min_length.\n                     ',
                    tunable=TunableLocalizedStringFactory()))),
        'max_length':
        Tunable(
            description=
            '\n             Max amount of characters the user can enter into the text box.\n             ',
            tunable_type=int,
            default=20)
    }

    def build_msg(self, dialog, msg, *additional_tokens):
        msg.max_length = self.max_length
        if self.min_length is not None:
            msg.min_length = self.min_length.length
            if self.min_length.tooltip is not None:
                msg.input_too_short_tooltip = dialog._build_localized_string_msg(
                    self.min_length.tooltip, *additional_tokens)
Ejemplo n.º 13
0
class InteractionOfInterest(AutoFactoryInit):
    __qualname__ = 'InteractionOfInterest'
    FACTORY_TUNABLES = {
        'affordance':
        TunableReference(
            description=
            '\n                The affordance that we are are timing for length of runtime.\n                ',
            manager=services.affordance_manager(),
            class_restrictions='SuperInteraction'),
        'tags':
        TunableSet(
            description=
            '\n                A set of tags that will match an affordance instead of looking\n                for a specific one.\n                ',
            tunable=TunableEnumEntry(Tag, Tag.INVALID)),
        'duration':
        TunableRange(
            description=
            '\n                The amount of time in sim hours that this interaction has to\n                run for this test to be considered passed.\n                ',
            tunable_type=int,
            default=10,
            minimum=1)
    }

    def get_expected_args(self):
        return {'interaction': event_testing.test_events.FROM_EVENT_DATA}

    def __call__(self, interaction=None):
        if interaction.affordance is self.affordance:
            return TestResult.TRUE
        if self.tags & interaction.get_category_tags():
            return TestResult.TRUE
        return TestResult(
            False,
            'Failed affordance check: {} is not {} and does not have any matching tags in {}.',
            interaction.affordance, self.affordance, self.tags)
Ejemplo n.º 14
0
class FormationTuning:
    GOAL_HEIGHT_LIMIT = TunableRange(
        description=
        '\n        Max value in meters between the height of the formation master and\n        the goals generated by a routing slave.\n        If the goals have a height different higher than this value, they\n        will be ignored even though the could be inside the valid constraint\n        around the master.\n        ',
        tunable_type=float,
        default=0.5,
        minimum=0)
Ejemplo n.º 15
0
class TunableMultiplier(HasTunableSingletonFactory, AutoFactoryInit):
    __qualname__ = 'TunableMultiplier'
    FACTORY_TUNABLES = {
        'base_value':
        Tunable(
            description=
            '\n            The basic value to return if no modifications are applied.\n            ',
            default=1,
            tunable_type=float),
        'multipliers':
        TunableList(
            description=
            '\n            A list of multipliers to apply to base_value.\n            ',
            tunable=TunableTuple(
                multiplier=TunableRange(
                    description=
                    '\n                    The multiplier to apply to base_value if the associated\n                    tests pass.\n                    ',
                    tunable_type=float,
                    default=1,
                    minimum=0),
                tests=TunableTestSet(
                    description=
                    '\n                    A series of tests that must pass in order for multiplier to\n                    be applied.\n                    '
                )))
    }

    def get_multiplier(self, participant_resolver):
        multiplier = self.base_value
        for multiplier_data in self.multipliers:
            while multiplier_data.tests.run_tests(participant_resolver):
                multiplier *= multiplier_data.multiplier
        return multiplier
class TimeOfDayComponent(Component,
                         HasTunableFactory,
                         component_name=types.TIME_OF_DAY_COMPONENT):
    __qualname__ = 'TimeOfDayComponent'
    DAILY_REPEAT = date_and_time.create_time_span(hours=24)
    FACTORY_TUNABLES = {
        'state_changes':
        TunableMapping(
            description=
            '\n            A mapping from state to times of the day when the state should be \n            set to a tuned value.\n            ',
            key_type=TunableStateTypeReference(
                description='The state to be set.'),
            value_type=TunableList(
                description='List of times to modify the state at.',
                tunable=TunableTuple(start_time=TunableRange(
                    float,
                    0,
                    description=
                    'The start time (24 hour clock time) for the Day_Time state.',
                    minimum=0,
                    maximum=24),
                                     value=TunableStateValueReference(
                                         description='New state value.'))))
    }

    def __init__(self, owner, *, state_changes):
        super().__init__(owner)
        self.state_changes = state_changes
        self.alarm_handles = []

    def _add_alarm(self, cur_state, game_clock, state, change):
        time_to_day = game_clock.time_until_hour_of_day(change.start_time)

        def change_state(_):
            self.owner.set_state(state, change.value)

        self.alarm_handles.append(
            alarms.add_alarm(self.owner,
                             time_to_day,
                             change_state,
                             repeating=True,
                             repeating_time_span=self.DAILY_REPEAT))
        if cur_state is None or time_to_day > cur_state[0]:
            return (time_to_day, change.value)
        return cur_state

    def on_add(self):
        game_clock_service = services.game_clock_service()
        for (state, changes) in self.state_changes.items():
            current_state = None
            for change in changes:
                current_state = self._add_alarm(current_state,
                                                game_clock_service, state,
                                                change)
            while current_state is not None:
                self.owner.set_state(state, current_state[1])

    def on_remove(self):
        for handle in self.alarm_handles:
            alarms.cancel_alarm(handle)
Ejemplo n.º 17
0
class PetGroupCostFunction(HasTunableFactory, AutoFactoryInit, CostFunctionBase):
    FACTORY_TUNABLES = {'maximum_distance': TunableRange(description='\n            Any distance to another Sim over this amount scores zero.\n            ', tunable_type=float, default=1.0, minimum=0), 'minimum_distance': TunableRange(description='\n            Any distance to another Sim under this amount scores zero.\n            ', tunable_type=float, default=1.5, minimum=0), 'required_distance': TunableRange(description='\n            Any position that requires the Sim to move less than this amount\n            scores zero. This encourages Sims to move.\n            ', tunable_type=float, default=0.75, minimum=0)}
    SIDE_ARC_START = math.cos(sims4.math.PI/4)
    SIDE_ARC_END = math.cos(sims4.math.PI*3/4)

    def __init__(self, sim, target, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._sim = sim
        self._target_ref = target.ref()

    def constraint_cost(self, position, orientation, routing_surface):
        target = self._target_ref()
        if target is None:
            return 0.0
        distance_to_position = (position - self._sim.position).magnitude()
        if distance_to_position < self.required_distance:
            return 0.0
        vector_to_pos = position - target.position
        distance_to_sim = vector_to_pos.magnitude()
        if distance_to_sim <= self.minimum_distance or distance_to_sim > self.maximum_distance:
            return 0.0
        else:
            unit_vector_to_sim = vector_to_pos/distance_to_sim
            fwd = target.transform.orientation.transform_vector(sims4.math.Vector3.Z_AXIS())
            angle = sims4.math.vector_dot(fwd, unit_vector_to_sim)
            if angle <= PetGroupCostFunction.SIDE_ARC_START and angle >= PetGroupCostFunction.SIDE_ARC_END:
                return -3.0
        return 0.0
Ejemplo n.º 18
0
class SocialGeometry:
    __qualname__ = 'SocialGeometry'
    __slots__ = ('focus', 'field', '_area', 'transform')
    GROUP_DISTANCE_CURVE = TunableCurve(
        description=
        '\n    A curve defining the score for standing a given distance away from other\n    Sims in the social group.\n    \n    Higher values (on the y-axis) encourage standing at that distance (on the\n    x-axis) away from other Sims.'
    )
    NON_GROUP_DISTANCE_CURVE = TunableCurve(
        description=
        '\n    A curve defining the score for standing a given distance away from other\n    Sims *not* in the social group.\n    \n    Higher values (on the y-axis) encourage standing at that distance (on the\n     x-axis) away from other Sims.'
    )
    GROUP_ANGLE_CURVE = TunableCurve(
        description=
        '\n    A curve defining the score for two Sims with this facing angle (in radians).\n    \n    An angle of zero (on the x-axis) means a Sims is facing another Sim, while\n    PI means a Sim is facing away.  Higher values (on the y-axis) encourage\n    that angular facing.'
    )
    OVERLAP_SCORE_MULTIPLIER = Tunable(
        float,
        1.0,
        description=
        'p\n    Higher values raise the importance of the "personal space" component of the\n    social scoring function.'
    )
    DEFAULT_SCORE_CUTOFF = TunableRange(
        float,
        0.8,
        minimum=0,
        maximum=1.0,
        description=
        '\n    Transforms scoring below cutoff * max_score are filtered out when joining / adjusting position'
    )
    NON_OVERLAPPING_SCORE_MULTIPLIER = Tunable(
        float,
        0.05,
        description='Minimum score multiplier for non-overlapping fields')
    SCORE_STRENGTH_MULTIPLIER = Tunable(
        float,
        3,
        description=
        '\n    Values > 1 will cause Sims to go further out of their way to be in perfect social arrangements.\n    This helps overcome distance attenuation for social adjustment since we want Sims to care more\n    about where they are positioned than how far they have to go to improve that position.'
    )
    SCORE_OFFSET_FOR_CURRENT_POSITION = Tunable(
        float,
        0.5,
        description=
        "\n    An additional score to apply to points that are virtually identical to the\n    Sim's current position if the Sim already has an entry in the geometry.\n    \n    Larger numbers provide more friction that will prevent Sims from moving\n    away from their current position unless the score of the new point makes\n    moving worthwhile."
    )

    def __init__(self, focus, field, transform):
        self.focus = focus
        self.field = field
        self.transform = transform
        self._area = None

    def __repr__(self):
        return 'SocialGeometry[Focus:{}]'.format(self.focus)

    @property
    def area(self):
        if self._area is None:
            self._area = self.field.area()
        return self._area
Ejemplo n.º 19
0
class _PortalRoutingSurfaceSpecified(HasTunableSingletonFactory,
                                     AutoFactoryInit):
    FACTORY_TUNABLES = {
        'surface_type':
        TunableEnumEntry(
            description=
            '\n            The surface type on which to create the portal.\n            ',
            tunable_type=SurfaceType,
            default=SurfaceType.SURFACETYPE_WORLD,
            invalid_enums=(SurfaceType.SURFACETYPE_UNKNOWN, )),
        'level_override':
        OptionalTunable(
            description=
            '\n            If enabled, allows this surface to have a level override.\n            ',
            tunable=TunableRange(
                description=
                '\n                The level to force this routing surface. This is useful for\n                picking out oceans since they are routing surface type POOL but\n                always on level 0.\n                ',
                tunable_type=int,
                default=0,
                minimum=-3,
                maximum=5))
    }

    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)
Ejemplo n.º 20
0
class RelationshipBitCountTest(HasTunableSingletonFactory, AutoFactoryInit,
                               BaseTest):
    FACTORY_TUNABLES = {
        'subject':
        TunableEnumFlags(
            description=
            '\n            Owner of the relationship.\n            ',
            enum_type=ParticipantTypeSingleSim,
            default=ParticipantTypeSingleSim.Actor),
        'rel_bit':
        TunablePackSafeReference(
            description=
            "\n            The type of relationship we're looking for.\n            \n            In other words, we're looking for any relationship\n            with this Rel Bit.\n            ",
            manager=services.get_instance_manager(
                sims4.resources.Types.RELATIONSHIP_BIT)),
        'relationship_count':
        TunableRange(
            description=
            "\n            The number of relationships we want to compare against\n            the sim's actual number of relationships.\n            ",
            tunable_type=int,
            minimum=0,
            default=0),
        'comparison_operator':
        TunableOperator(
            description=
            "\n            The operator to use to compare the sim's\n            actual relationship count vs. the tuned\n            Relationship Count.\n            ",
            default=Operator.EQUAL)
    }

    def get_expected_args(self):
        return {'sim_infos': self.subject}

    @cached_test
    def __call__(self, sim_infos):
        if self.rel_bit is None:
            return TestResult(
                False,
                'Failed relationship bit count test: Rel Bit is not available due to pack-safeness'
            )
        sim_info_manager = services.sim_info_manager()
        for sim_info in sim_infos:
            rel_tracker = sim_info.relationship_tracker
            actual_rel_count = 0
            for other_sim_info_id in sim_info.relationship_tracker.target_sim_gen(
            ):
                other_sim_info = sim_info_manager.get(other_sim_info_id)
                if other_sim_info is None:
                    continue
                if rel_tracker.has_bit(other_sim_info_id, self.rel_bit):
                    actual_rel_count += 1
            threshold = sims4.math.Threshold(self.relationship_count,
                                             self.comparison_operator)
            if not threshold.compare(actual_rel_count):
                operator_symbol = Operator.from_function(
                    self.comparison_operator).symbol
                return TestResult(
                    False,
                    'Failed relationship bit count test: Actual Relationship Count ({}) {} Tuned Relationship Count ({})',
                    actual_rel_count, operator_symbol, self.relationship_count)
        return TestResult.TRUE
Ejemplo n.º 21
0
class ShortTermContextRelationshipTrack(RelationshipTrack):
    __qualname__ = 'ShortTermContextRelationshipTrack'
    INSTANCE_TUNABLES = {
        'socialization_decay_modifier':
        TunableRange(
            description=
            '\n            A multiplier to apply to the decay rate if the two Sims that this\n            relationship track applies to are socializing.\n            ',
            tunable_type=float,
            default=1,
            minimum=0)
    }

    @classproperty
    def is_short_term_context(cls):
        return True

    def on_add(self):
        super().on_add()
        sim = self.tracker.relationship.find_sim()
        target = self.tracker.relationship.find_target_sim()
        if sim is not None and target is not None and sim.is_in_group_with(
                target):
            self.apply_social_group_decay()

    def apply_social_group_decay(self):
        if self.socialization_decay_modifier != 1:
            self.add_decay_rate_modifier(self.socialization_decay_modifier)

    def remove_social_group_decay(self):
        if self.socialization_decay_modifier != 1:
            self.remove_decay_rate_modifier(self.socialization_decay_modifier)
Ejemplo n.º 22
0
class _BroadcasterEffectTestedOneShot(_BroadcasterEffectTested):
    FACTORY_TUNABLES = {
        'affected_object_cap':
        OptionalTunable(
            description=
            '\n            If enabled, specify the maximum number of objects that can\n            be affected by this particular effect, per broadcaster. This\n            is a soft- cap, since the data does not persist across\n            multiple broadcaster requests nor save games.\n            ',
            tunable=TunableRange(
                description=
                '\n                The maximum number of objects that can be affected by\n                this broadcaster.\n                ',
                tunable_type=int,
                minimum=1,
                default=1))
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._object_counter = weakref.WeakKeyDictionary()

    def _should_apply_broadcaster_effect(self, broadcaster, affected_object):
        result = super()._should_apply_broadcaster_effect(
            broadcaster, affected_object)
        if not result:
            return result
        if self.affected_object_cap is not None:
            if broadcaster not in self._object_counter:
                self._object_counter[broadcaster] = 0
            if self._object_counter[broadcaster] >= self.affected_object_cap:
                return False
            self._object_counter[broadcaster] += 1
        return result
Ejemplo n.º 23
0
class ContentSetTuning:
    POSTURE_PENALTY_MULTIPLIER = TunableRange(
        description=
        '\n        Multiplier applied to content score if sim will be removed from posture.\n        ',
        tunable_type=float,
        default=0.5,
        maximum=1)
Ejemplo n.º 24
0
class ItemCost(ItemCostBase, AutoFactoryInit, HasTunableSingletonFactory):
    UNAVAILABLE_TOOLTIP_HEADER = TunableLocalizedStringFactory(
        description=
        '\n        A string to be used as a header for a bulleted list of items that the\n        Sim is missing in order to run this interaction.\n        '
    )
    AVAILABLE_TOOLTIP_HEADER = TunableLocalizedStringFactory(
        description=
        '\n        A string to be used as a header for a bulleted list of items that the\n        Sim will consume in order to run this interaction.\n        '
    )
    FACTORY_TUNABLES = {
        'ingredients':
        TunableList(
            description=
            '\n            List of tuples of Objects and Quantity, which will indicate\n            the cost of items for this interaction to run\n            ',
            tunable=TunableTuple(
                description=
                '\n                Pair of Object and Quantity needed for this interaction\n                ',
                ingredient=TunableReference(
                    description=
                    '\n                    Object reference of the type of game object needed.\n                    ',
                    manager=services.definition_manager()),
                quantity=TunableRange(
                    description=
                    '\n                    Quantity of objects needed\n                    ',
                    tunable_type=int,
                    default=1,
                    minimum=1),
                missing_ingredient_additional_text=OptionalTunable(
                    description=
                    '\n                    If set, this text is inserted on a new line following a missing ingredient.\n                    ',
                    tunable=TunableLocalizedString(
                        default=None,
                        description='The string key of the text description'
                    ))))
    }
Ejemplo n.º 25
0
class DayOfSeason(HasTunableFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'week_of_season':
        TunableRange(
            description=
            '\n            Which week of the season this is.  First week is week 0.\n            ',
            tunable_type=int,
            default=0,
            minimum=0,
            maximum=7),
        'day_of_week':
        TunableEnumEntry(
            description='\n            Day of the week.\n            ',
            tunable_type=Days,
            default=Days.SUNDAY)
    }

    def __init__(self, season_start_time, **kwargs):
        super().__init__(**kwargs)
        self._date_and_time = season_start_time + create_time_span(
            days=self.day_of_season)

    def __repr__(self):
        return repr(self._date_and_time)

    @property
    def date_and_time(self):
        return self._date_and_time

    @property
    def day_of_season(self):
        return self.week_of_season * date_and_time.DAYS_PER_WEEK + self.day_of_week.value
Ejemplo n.º 26
0
class PortalTuning:
    SURFACE_PORTAL_HEIGH_OFFSET = TunableRange(
        description=
        '\n        A height offset on meters increase the height of the raycast test\n        to consider two connecting portals valid over an objects footprint.\n        For example this height is high enough so two portals on counters pass\n        a raycast test over a stove or a sink (low objects), but is not high\n        enough to pass over a microwave (which would cause our sims to clip\n        through the object when transitioning through the portal.\n        ',
        tunable_type=float,
        default=0.2,
        minimum=0)
class _ObjectBasedWaitingCustomerCap(HasTunableSingletonFactory,
                                     AutoFactoryInit):
    FACTORY_TUNABLES = {
        'object_count_waiting_customer_cap':
        TunableMapping(
            description=
            '\n            For each amount defined, set the cap to waiting customers.\n            \n            For this test we are using number of Vet Clinic exam tables.\n            \n            If the actual count exceeds the all the keys,\n            then it will use the cap for the key with the highest value.\n            ',
            set_default_as_first_entry=True,
            key_type=Tunable(
                description=
                '\n                Number of exam tables.\n                ',
                tunable_type=int,
                default=0),
            value_type=TunableRange(
                description=
                '\n                Value to cap waiting customers at.\n                ',
                tunable_type=int,
                default=2,
                minimum=0))
    }

    def get_cap_amount(self):
        zone_director = get_vet_clinic_zone_director()
        if zone_director is None:
            return 0
        exam_table_thresholds = sorted(
            self.object_count_waiting_customer_cap.keys(), reverse=True)
        num_exam_tables = zone_director.num_exam_tables
        for threshold in exam_table_thresholds:
            if num_exam_tables >= threshold:
                return self.object_count_waiting_customer_cap[threshold]
        return 0
class FadeChildrenElement(elements.ParentElement, HasTunableFactory):
    __qualname__ = 'FadeChildrenElement'
    FACTORY_TUNABLES = {'opacity': TunableRange(description='\n            The target opacity for the children.\n            ', tunable_type=float, default=0, minimum=0, maximum=1), '_parent_object': TunableEnumEntry(description='\n            The participant of an interaction whose children should be hidden.\n            ', tunable_type=ParticipantType, default=ParticipantType.Object), 'fade_duration': OptionalTunable(TunableRealSecond(description='\n                The number of seconds it should take for objects to fade out and\n                in.\n                ', default=0.25), disabled_name='use_default_fade_duration', enabled_name='use_custom_fade_duration'), 'fade_objects_on_ground': Tunable(description='\n            If checked, objects at height zero will fade. By default, objects \n            at ground level (like stools slotted into counters) will not fade.\n            ', tunable_type=bool, default=False)}

    def __init__(self, interaction, *, opacity, _parent_object, fade_duration, fade_objects_on_ground, sequence=()):
        super().__init__()
        self.interaction = interaction
        self.opacity = opacity
        self.parent_object = interaction.get_participant(_parent_object)
        if fade_duration is None:
            self.fade_duration = ClientObjectMixin.FADE_DURATION
        else:
            self.fade_duration = fade_duration
        self.fade_objects_on_ground = fade_objects_on_ground
        self.sequence = sequence
        self.hidden_objects = weakref.WeakKeyDictionary()

    def _run(self, timeline):

        def begin(_):
            for obj in self.parent_object.children_recursive_gen():
                if self.fade_objects_on_ground or obj.position.y == self.parent_object.position.y:
                    pass
                opacity = obj.opacity
                self.hidden_objects[obj] = opacity
                obj.fade_opacity(self.opacity, self.fade_duration)

        def end(_):
            for (obj, opacity) in self.hidden_objects.items():
                obj.fade_opacity(opacity, self.fade_duration)

        return timeline.run_child(build_critical_section_with_finally(begin, self.sequence, end))
Ejemplo n.º 29
0
class ApplyForScholarshipLoot(BaseLootOperation):
    APPLICATION_RESULT_DELAY_TIME = TunableRange(
        description=
        "\n        The tunable number of Sim hours to wait before resolving a scholarship\n        applicant's status. \n        \n        At the point the delay ends, 1) the Sim will be able to check their application\n        status on a computer and 2) an application response letter will be scheduled\n        for delivery to the home lot.\n        ",
        tunable_type=int,
        default=1440,
        minimum=1)
    FACTORY_TUNABLES = {
        'scholarship':
        TunableReference(
            description=
            '\n            The organization for which this drama node is scheduling venue events.\n            ',
            manager=services.get_instance_manager(
                sims4.resources.Types.SNIPPET),
            class_restrictions='Scholarship')
    }
    MAX_SCORE = 100

    def __init__(self, *args, scholarship, **kwargs):
        super().__init__(*args, **kwargs)
        self._scholarship = scholarship

    def _apply_to_subject_and_target(self, subject, target, resolver):
        degree_tracker = subject.degree_tracker
        if degree_tracker is None:
            logger.error(
                "({}) is applying for a scholarship, but ({})'s degree tracker is None. Application failed.",
                str(subject))
            return
        degree_tracker.process_scholarship_application(
            self._scholarship,
            date_and_time.create_time_span(
                hours=self.APPLICATION_RESULT_DELAY_TIME))
Ejemplo n.º 30
0
class FishingBait(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'bait_name':
        TunableLocalizedStringFactory(
            description='\n            Name of fishing bait.\n            '),
        'bait_description':
        TunableLocalizedStringFactory(
            description=
            '\n            Description of fishing bait.\n            '),
        'bait_icon_definition':
        TunableReference(
            description=
            '\n            Object definition that will be used to render icon of fishing bait.\n            ',
            manager=services.definition_manager()),
        'bait_buff':
        TunableReference(
            description='\n            Buff of fishing bait.\n            ',
            manager=services.buff_manager()),
        'bait_priority':
        TunableRange(
            description=
            '\n            The priority of the bait. When an object can be categorized into\n            multiple fishing bait categories, the highest priority category \n            will be chosen.\n            ',
            tunable_type=int,
            default=1,
            minimum=1)
    }