Beispiel #1
0
class SeasonsTuning:
    STARTING_SEASON = StartingSeason.TunableFactory()
    SEASON_LENGTH_OPTIONS = TunableMapping(
        description=
        '\n        A mapping of individual season length options to the length of time\n        they are set to.\n        ',
        key_type=TunableEnumEntry(tunable_type=SeasonLength,
                                  default=SeasonLength.NORMAL,
                                  binary_type=EnumBinaryExportType.EnumUint32),
        value_type=TunableTimeSpan(
            description=
            '\n            Length of this season option, in days.\n            ',
            default_days=7,
            locked_args={
                'hours': 0,
                'minutes': 0
            },
            export_modes=ExportModes.All),
        tuple_name='SeasonLengthOptions',
        export_modes=ExportModes.All)
    SEASON_TYPE_MAPPING = TunableMapping(
        description=
        '\n        A mapping of the season type to the season resource it will use.\n        ',
        key_type=TunableEnumEntry(
            description='\n            The season.\n            ',
            tunable_type=SeasonType,
            default=SeasonType.SUMMER),
        value_type=TunableReference(
            description=
            '\n            Season resource that will be mapped to this season.\n            ',
            manager=services.get_instance_manager(Types.SEASON),
            pack_safe=True))
Beispiel #2
0
class LotTuningMaps:
    LOT_TO_LOTTUNING_MAP = TunableMapping(description="\n            Mapping of Lot Description ID to lot tuning. This is a reference to \n            a specific lot in one of our regions. e.g. Goth's mansion lot.\n            ", key_name='Lot Description ID', key_type=TunableLotDescription(pack_safe=True), value_name='Lot Tuning', value_type=LotTuning.TunablePackSafeReference())
    STREET_TO_LOTTUNING_MAP = TunableMapping(description='\n            Mapping of Street Description ID to lot tuning. Street and world\n            are analogous terms. e.g. suburbs street in Garden District.\n            \n            This represents the tuning for all lots within this street that does\n            not have a specific LotTuning specified for itself in the \n            LOT_TO_LOTTUNING_MAP.\n            ', key_name='Street Description ID', key_type=TunableWorldDescription(pack_safe=True), value_name='Lot Tuning', value_type=LotTuning.TunablePackSafeReference())
    REGION_TO_LOTTUNING_MAP = TunableMapping(description='\n            Mapping of Region Description ID to spawner tuning. Region and \n            neighborhood are analogous terms. e.g. Garden District.\n            \n            This represents the tuning for all lots in the region that does\n            not have a specific LotTuning specified for itself in either the \n            LOT_TO_LOTTUNING_MAP or via STREET_TO_LOTTUNING_MAP.\n            ', key_name='Region Description ID', key_type=TunableRegionDescription(pack_safe=True), value_name='Lot Tuning', value_type=LotTuning.TunablePackSafeReference())

    @classmethod
    def get_lot_tuning(cls):
        current_zone = services.current_zone()
        lot = current_zone.lot
        if lot is None:
            logger.warn('Attempting to get LotTuning when the current zone does not have a lot.', owner='manus')
            return
        (world_description_id, lot_description_id) = services.get_world_and_lot_description_id_from_zone_id(current_zone.id)
        lot_tuning = cls.LOT_TO_LOTTUNING_MAP.get(lot_description_id)
        if lot_tuning is not None:
            return lot_tuning
        lot_tuning = cls.STREET_TO_LOTTUNING_MAP.get(world_description_id, None)
        if lot_tuning is not None:
            return lot_tuning
        neighborhood_id = current_zone.neighborhood_id
        if neighborhood_id == 0:
            logger.warn('Attempting to get LotTuning when the current zone does not have a neighborhood.', owner='manus')
            return
        neighborhood_proto_buff = services.get_persistence_service().get_neighborhood_proto_buff(neighborhood_id)
        region_id = neighborhood_proto_buff.region_id
        lot_tuning = cls.REGION_TO_LOTTUNING_MAP.get(region_id, None)
        return lot_tuning
Beispiel #3
0
class IngredientTuning:
    __qualname__ = 'IngredientTuning'
    INGREDIENT_QUALITY_MAPPING = TunableMapping(description='\n        Mapping of all possible ingredient quality states to what possible\n        states will the ingredients have.\n        e.g. High quality ingredients need to be mapped to gardening high \n        quality, fish high quality or any state that will indicate what \n        high quality means on a different system.\n        ', key_type=ObjectStateValue.TunableReference(description='\n            The states that will define the ingredient quality.\n            '), value_type=TunableTuple(description='\n            Definition of the ingredient quality state.  This will define\n            the quality boost on the recipe and the possible states an \n            ingredient can have to have this state.\n            ', quality_boost=Tunable(description='\n                Value that will be added to the quality commodity whenever\n                this state is added.\n                ', tunable_type=int, default=1), state_value_list=TunableList(description='\n                List of ingredient states that will give this level of \n                ingredient quality.\n                ', tunable=ObjectStateValue.TunableReference(description='\n                    The states that will define the ingredient quality.\n                    '))))
    INGREDIENT_TAG_DISPLAY_MAPPING = TunableMapping(description='\n        Mapping of all object tags to their localized string that will display\n        on the ingredient list.\n        This will be used for displaying on the recipe\'s when an ingredient is \n        tuned by tag instead of object definition.\n        Example: Display objects of rag FISH as string "Any Fish"\n        ', key_type=TunableEnumEntry(description='\n            Tag corresponding at an ingredient type that can be used in a\n            recipe.\n            ', tunable_type=tag.Tag, default=tag.Tag.INVALID), value_type=TunableLocalizedStringFactory())
    INGREDIENT_TAG = TunableEnumEntry(description='\n        Tag to look for when iterating through objects to know if they are \n        ingredients.\n        All ingredients should be tuned with this tag.\n        ', tunable_type=tag.Tag, default=tag.Tag.INVALID)

    @classmethod
    def get_quality_bonus(cls, ingredient):
        for quality_details in IngredientTuning.INGREDIENT_QUALITY_MAPPING.values():
            for state_value in quality_details.state_value_list:
                while ingredient.state_value_active(state_value):
                    return quality_details.quality_boost
        return 0

    @classmethod
    def get_ingredient_quality_state(cls, quality_bonus):
        state_to_add = None
        bonus_selected = None
        for (quality_state_value, quality_details) in IngredientTuning.INGREDIENT_QUALITY_MAPPING.items():
            while (bonus_selected is None or quality_details.quality_boost <= bonus_selected) and bonus_selected >= quality_bonus:
                bonus_selected = quality_details.quality_boost
                state_to_add = quality_state_value
        return state_to_add

    @classmethod
    def get_ingredient_string_for_tag(cls, tag):
        string_factory = IngredientTuning.INGREDIENT_TAG_DISPLAY_MAPPING.get(tag)
        if string_factory:
            return string_factory()
        return
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)
Beispiel #5
0
class AgingTuning:
    AGING_DATA = TunableMapping(description='\n        On a per-species level, define all age-related data.\n        ', key_type=TunableEnumEntry(description='\n            The species this aging data applies to.\n            ', tunable_type=Species, default=Species.HUMAN, invalid_enums=(Species.INVALID,), binary_type=EnumBinaryExportType.EnumUint32), value_type=AgingData.TunableFactory(), tuple_name='AgingDataMapping')
    AGING_SAVE_LOCK_TOOLTIP = TunableLocalizedStringFactory(description='\n        The tooltip to show in situations where save-lock during Age Up is\n        necessary, i.e. when babies or non-NPC Sims age up.\n        \n        This tooltip is provided one token: the Sim that is aging up.\n        ')
    AGE_SPEED_SETTING_MULTIPLIER = TunableMapping(description='\n        A mapping between age speeds and the multiplier that those speeds\n        correspond to.\n        ', key_type=TunableEnumEntry(description='\n            The age speed that will be mapped to its multiplier.\n            ', tunable_type=AgeSpeeds, default=AgeSpeeds.NORMAL), value_type=Tunable(description="\n            The multiplier by which to adjust the lifespan based on user age\n            speed settings. Setting this to 2 for 'Slow' speed will double the\n            Sim's age play time in that setting.\n            ", tunable_type=float, default=1))
    AGE_PROGRESS_UPDATE_TIME = Tunable(description='\n        The update rate, in Sim Days, of age progression in the UI.\n        ', tunable_type=float, default=0.2)
    AGE_SUPPRESSION_ALARM_TIME = TunableSimMinute(description='\n        Amount of time in sim seconds to suppress aging.\n        ', default=5, minimum=1)

    @classmethod
    def get_aging_data(cls, species):
        return cls.AGING_DATA[species]
Beispiel #6
0
class CASStoriesTuning:
    CAS_STORIES = TunableTuple(
        description=
        '\n            Tuning for the CAS Stories sim-creation flow.\n            ',
        questions_per_pack=TunableMapping(
            description=
            '\n                Mapping between the number of packs available and the number of\n                base game questions and questions per pack that should be asked.\n                ',
            key_type=Tunable(
                description=
                '\n                    The number of available packs.\n                    ',
                tunable_type=int,
                default=0),
            value_type=TunableTuple(
                description=
                '\n                    The number of questions that should be asked.\n                    ',
                base_game_questions=Tunable(
                    description=
                    '\n                        The number of base game questions to ask.\n                        ',
                    tunable_type=int,
                    default=0),
                per_pack_questions=Tunable(
                    description=
                    '\n                        The number of pack questions to ask per pack.\n                        ',
                    tunable_type=int,
                    default=0),
                export_class_name='CasStoriesQuestionCountTuple'),
            tuple_name='CasStoriesQuestionsPerPackKeyValue'),
        funds_traits=TunableMapping(
            description=
            '\n                Mapping between specific traits and the amount of starting\n                household funds to give to a sim with that trait.\n                ',
            key_type=TunableReference(
                description=
                '\n                    Reference to the trait.\n                    ',
                manager=services.get_instance_manager(Types.TRAIT)),
            value_type=Tunable(
                description=
                '\n                    The household starting funds.\n                    ',
                tunable_type=int,
                default=0),
            tuple_name='CasStoriesFundsPerTraitKeyValue'),
        additional_sims_funds_percentage=TunableRange(
            description=
            '\n                If additional CAS Stories sims are added to a household, this is\n                the percentage of their normal funding to add to the household\n                funds as additonal funding. For instance, if we have 1 sim with\n                a 10,000 simoleon trait and a second sim with a 5,000 simoleon\n                trait and this is tuned to .5, the resulting household income\n                would be 10,000 + .5 * 5,000 = 12,500.\n                ',
            tunable_type=float,
            default=0.75,
            minimum=0,
            maximum=1),
        silouetted_sim_info=TunableResourceKey(
            description=
            '\n                The SimInfo file to use for the silouetted sim in CAS Stories.\n                ',
            default=None,
            resource_types=(sims4.resources.Types.SIMINFO, )),
        export_modes=ExportModes.ClientBinary,
        export_class_name='CasStoriesTuning')
Beispiel #7
0
class OutfitGeneratorRandomizationMixin:
    INSTANCE_TUNABLES = {
        'filter_flag':
        TunableEnumFlags(
            description=
            '\n            Define how to handle part randomization for the generated outfit.\n            ',
            enum_type=OutfitFilterFlag,
            default=OutfitFilterFlag.USE_EXISTING_IF_APPROPRIATE
            | OutfitFilterFlag.USE_VALID_FOR_LIVE_RANDOM,
            allow_no_flags=True),
        'body_type_chance_overrides':
        TunableMapping(
            description=
            '\n            Define body type chance overrides for the generate outfit. For\n            example, if BODYTYPE_HAT is mapped to 100%, then the outfit is\n            guaranteed to have a hat if any hat matches the specified tags.\n            \n            If used in an appearance modifier, these body types will contribute\n            to the flags that determine which body types can be generated,\n            regardless of their percent chance.\n            ',
            key_type=BodyType,
            value_type=TunablePercent(
                description=
                '\n                The chance that a part is applied to the corresponding body\n                type.\n                ',
                default=100)),
        'body_type_match_not_found_policy':
        TunableMapping(
            description=
            '\n            The policy we should take for a body type that we fail to find a\n            match for. Primary example is to use MATCH_NOT_FOUND_KEEP_EXISTING\n            for generating a tshirt and making sure a sim wearing full body has\n            a lower body cas part.\n            \n            If used in an appearance modifier, these body types will contribute\n            to the flags that determine which body types can be generated.\n            ',
            key_type=BodyType,
            value_type=MatchNotFoundPolicy)
    }
    FACTORY_TUNABLES = INSTANCE_TUNABLES

    def get_body_type_flags(self):
        tuned_flags = 0
        for body_type in itertools.chain(
                self.body_type_chance_overrides.keys(),
                self.body_type_match_not_found_policy.keys()):
            tuned_flags |= 1 << body_type
        return tuned_flags or BodyTypeFlag.CLOTHING_ALL

    def _generate_outfit(self,
                         sim_info,
                         outfit_category,
                         outfit_index=0,
                         tag_list=(),
                         seed=None):
        sim_info.generate_outfit(
            outfit_category,
            outfit_index=outfit_index,
            tag_list=tag_list,
            filter_flag=self.filter_flag,
            body_type_chance_overrides=self.body_type_chance_overrides,
            body_type_match_not_found_overrides=self.
            body_type_match_not_found_policy,
            seed=seed)
Beispiel #8
0
class StreetPlexExteriorChangeEffect(StreetEffect):
    INSTANCE_TUNABLES = {
        'enact_exterior_house_descriptions':
        TunableMapping(
            description=
            "\n            When enacted, a reference to the HouseDescription resource to use to \n            select the Lot Template.  Leaving unset makes no change on enact.\n            The Street's Zones are matched to find which House Descriptions should\n            be applied.  Only Zones that have matching Lot Descriptions and are on\n            the current Street will be modified.\n            ",
            key_type=TunableLotDescription(pack_safe=True),
            value_type=TunableHouseDescription(pack_safe=True)),
        'repeal_exterior_house_descriptions':
        TunableMapping(
            description=
            "\n            When repealed, a reference to the HouseDescription resource to use to \n            select the Lot Template.  Leaving unset makes no change on repeal.\n            The Street's Zones are matched to find which House Descriptions should\n            be applied.  Only Zones that have matching Lot Descriptions and are on\n            the current Street will be modified.\n            ",
            key_type=TunableLotDescription(pack_safe=True),
            value_type=TunableHouseDescription(pack_safe=True))
    }

    def _set_exterior_house_description(self, house_descriptions):
        if not house_descriptions:
            return
        zone_ids = get_zone_ids_from_street(self._street)
        if not zone_ids:
            return
        distributor = Distributor.instance()
        persistence_service = services.get_persistence_service()
        for zone_id in zone_ids:
            zone_data = persistence_service.get_zone_proto_buff(zone_id)
            zone_world_description_id = services.get_world_description_id(
                zone_data.world_id)
            zone_lot_description_id = services.get_lot_description_id(
                zone_data.lot_id, zone_world_description_id)
            for (lot_description_id,
                 house_description_id) in house_descriptions.items():
                if lot_description_id == zone_lot_description_id:
                    zone_data.pending_plex_exterior_house_desc_id = house_description_id
                    plex_update_msg = Lot_pb2.LotPlexExteriorUpdate()
                    plex_update_msg.zone_id = zone_id
                    plex_update_msg.plex_exterior_house_desc_id = house_description_id
                    distributor.add_event(
                        Consts_pb2.MSG_SET_PLEX_EXTERIOR_HOUSE_DESC,
                        plex_update_msg)
                    break

    def enact(self):
        self._set_exterior_house_description(
            self.enact_exterior_house_descriptions)

    def repeal(self):
        self._set_exterior_house_description(
            self.repeal_exterior_house_descriptions)
Beispiel #9
0
class TunableEnvironmentScoreModifiers(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {'mood_modifiers': TunableMapping(description='\n                Modifiers to apply to a given Mood for the environment scoring of an object.\n                ', key_type=TunableReference(description='\n                    The Mood we want to modify for objects in question.\n                    ', manager=services.get_instance_manager(sims4.resources.Types.MOOD)), value_type=TunableModifiers(description="\n                    Modifiers to apply to an object's environment score\n                    "), key_name='mood', value_name='modifiers'), 'negative_modifiers': OptionalTunable(description="\n                Modifiers for an object's negative environment score\n                ", tunable=TunableModifiers(), enabled_by_default=False), 'positive_modifiers': OptionalTunable(description="\n                Modifiers for an object's positive environment score\n                ", tunable=TunableModifiers(), enabled_by_default=False)}
    DEFAULT_MODIFIERS = (0, 1)

    def combine_modifiers(self, object_mood_modifiers, object_negative_modifiers, object_positive_modifiers):
        new_mood_modifiers = {}
        new_negative_modifiers = object_negative_modifiers
        new_positive_modifiers = object_positive_modifiers
        for (mood, modifiers) in object_mood_modifiers.items():
            new_mood_modifiers[mood] = modifiers
        for (mood, modifiers) in self.mood_modifiers.items():
            old_modifiers = new_mood_modifiers.get(mood, (0, 1))
            new_mood_modifiers[mood] = (old_modifiers[0] + modifiers.add_modifier, old_modifiers[1]*modifiers.multiply_modifier)
        new_modifiers = self.get_negative_modifiers()
        new_negative_modifiers = (new_negative_modifiers[0] + new_modifiers[0], new_negative_modifiers[1]*new_modifiers[1])
        new_modifiers = self.get_positive_modifiers()
        new_positive_modifiers = (new_positive_modifiers[0] + new_modifiers[0], new_positive_modifiers[1]*new_modifiers[1])
        return (new_mood_modifiers, new_negative_modifiers, new_positive_modifiers)

    def get_mood_modifiers(self, mood):
        mood_mods = self.mood_modifiers.get(mood)
        if mood_mods is not None:
            return (mood_mods.add_modifier, mood_mods.multiply_modifier)
        return self.DEFAULT_MODIFIERS

    def get_negative_modifiers(self):
        if self.negative_modifiers is not None:
            return (self.negative_modifiers.add_modifier, self.negative_modifiers.multiply_modifier)
        return self.DEFAULT_MODIFIERS

    def get_positive_modifiers(self):
        if self.positive_modifiers is not None:
            return (self.positive_modifiers.add_modifier, self.positive_modifiers.multiply_modifier)
        return self.DEFAULT_MODIFIERS
class NarrativeAwareComponent(Component,
                              HasTunableFactory,
                              AutoFactoryInit,
                              component_name=NARRATIVE_AWARE_COMPONENT):
    FACTORY_TUNABLES = {
        'narrative_state_mapping':
        TunableMapping(
            description=
            '\n            A tunable mapping linking a narrative to the states the component\n            owner should have.\n            ',
            key_type=TunableReference(
                description=
                '\n                The narrative we are interested in.\n                ',
                manager=services.get_instance_manager(Types.NARRATIVE)),
            value_type=TunableList(
                description=
                '\n                A tunable list of states to apply to the owning object of\n                this component when this narrative is active.\n                ',
                tunable=TunableStateValueReference(pack_safe=True)))
    }

    def on_add(self):
        self.on_narratives_set(services.narrative_service().active_narratives)

    def on_finalize_load(self):
        self.on_narratives_set(services.narrative_service().active_narratives)

    def on_narratives_set(self, narratives):
        for narrative in narratives:
            if narrative in self.narrative_state_mapping:
                for state_value in self.narrative_state_mapping[narrative]:
                    self.owner.set_state(state_value.state, state_value)
Beispiel #11
0
class Street(HasTunableReference, metaclass=HashedTunedInstanceMetaclass, manager=services.street_manager()):
    WORLD_DESCRIPTION_TUNING_MAP = TunableMapping(description='\n        A mapping between Catalog world description and street tuning instance.\n        This way we can find out what world description the current zone\n        belongs to at runtime then grab its street tuning instance.\n        ', key_type=TunableWorldDescription(description='\n            Catalog-side World Description.\n            ', pack_safe=True), value_type=TunableReference(description="\n            Street Tuning instance. This is retrieved at runtime based on what\n            the active zone's world description is.\n            ", pack_safe=True, manager=services.street_manager()), key_name='WorldDescription', value_name='Street')
    INSTANCE_TUNABLES = {'open_street_director': TunablePackSafeReference(description='\n            The Scheduling Open Street Director to use for this world file.\n            This open street director will be able to load object layers and\n            spin up situations.\n            ', manager=services.get_instance_manager(sims4.resources.Types.OPEN_STREET_DIRECTOR)), 'travel_lot': OptionalTunable(description='\n            If enabled then this street will have a specific lot that it will\n            want to travel to when we travel to this "street."\n            ', tunable=TunableLotDescription(description='\n                The specific lot that we will travel to when asked to travel to\n                this street.\n                ')), 'townie_demographics': TunableTuple(description='\n            Townie population demographics for the street.\n            ', target_population=OptionalTunable(description='\n                If enabled, Sims created for other purposes will passively be\n                assigned to live on this street, gaining the filter features.\n                Sims are assigned out in round robin fashion up until all\n                streets have reached their target, after which those streets\n                will be assigned Sims in round robin fashion past their target.\n                \n                If disabled, this street will not passively be assigned townies\n                unless the Lives On Street filter explicitly requires the\n                Sim to be on the street.\n                ', tunable=TunableRange(description="\n                    The ideal number of townies that live on the street.\n                    \n                    0 is valid if you don't want Sims to live on this street\n                    while other streets haven't met their target population.\n                    ", tunable_type=int, default=1, minimum=0)), filter_features=TunableList(description='\n                Sims created as townies living on this street, they will gain\n                one set of features in this list. Features are applied as\n                Sim creation tags and additional filter terms to use.\n                ', tunable=TunableTuple(description='\n                    ', filter_terms=TunableList(description='\n                        Filter terms to inject into the filter.\n                        ', tunable=FilterTermVariant(conform_optional=True)), sim_creator_tags=TunableReference(description="\n                        Tags to inject into the filter's Sim template.\n                        ", manager=services.get_instance_manager(sims4.resources.Types.TAG_SET), allow_none=True, class_restrictions=('TunableTagSet',)), sim_name_type=TunableEnumEntry(description='\n                        What type of name the sim should have.\n                        ', tunable_type=SimNameType, default=SimNameType.DEFAULT), weight=TunableRange(description='\n                        Weighted chance.\n                        ', tunable_type=float, default=1, minimum=0)))), 'valid_conditional_layers': TunableSet(description='\n            A list of all of the conditional_layers on this Street.\n            ', tunable=TunableReference(description='\n                A reference to a conditional layer that exists on this Street.\n                ', manager=services.get_instance_manager(sims4.resources.Types.CONDITIONAL_LAYER), pack_safe=True)), 'tested_conditional_layers': TunableList(description='\n            The list of conditional layers that will load in to the the street\n            if its tests pass.\n            \n            NOTE: Only a subset of tests are registered to listen for updates.\n            Check with your GPE if you expect to have the conditional layers update\n            with test events. Otherwise, they will only be tested on zone-load.\n            ', tunable=TunableTuple(description='\n                A list of all of the conditional_layers to load into this Street.\n                ', conditional_layer=TunableReference(description='\n                    A reference to a conditional layer that exists on this Street.\n                    ', manager=services.get_instance_manager(sims4.resources.Types.CONDITIONAL_LAYER), pack_safe=True), tests=TunableGlobalTestList(description='\n                    The tests that must pass in order for this conditional layer\n                    to be loaded in. If tests are empty, the conditional layer\n                    is considered valid.\n                    '), process_after_event_handled=Tunable(description='\n                     When True, conditional layer requests triggered by the test\n                     events will be ordered to prioritize client-layer requests\n                     first, then gameplay-layers.\n                     ', tunable_type=bool, default=False), test_on_managed_world_edit_mode_load=Tunable(description='\n                    By default, conditional layers are not tested and started when entering\n                    from Managed World Edit Mode.  Those layers which are enabled via this\n                    option will be tested and started even in Managed World Edit Mode.\n                    Generally these should be Client Only layers, but no such restriction is\n                    enforced.\n                    ', tunable_type=bool, default=False))), 'beaches': TunableList(description='\n            List of locations to place beaches.\n            ', tunable=TunableTuple(description='\n                Beach creation data.\n                ', position=TunableVector3(description='\n                    The position to create the beach at.\n                    ', default=TunableVector3.DEFAULT_ZERO), forward=TunableVector2(description='\n                    The forward vector of the beach object.\n                    ', default=Vector2.Y_AXIS())), unique_entries=True), 'civic_policy': StreetProvider.TunableFactory(description='\n            Tuning to control the civic policy voting and enactment process for\n            a street.\n            '), 'initial_street_eco_footprint_override': OptionalTunable(description='\n            If enabled, overrides the initial value of the street eco footprint\n            statistic.\n            ', tunable=Tunable(description='\n                The initial value of the street eco footprint statistic.\n                ', tunable_type=float, default=0))}
    ZONE_IDS_BY_STREET = None
    street_to_lot_id_to_zone_ids = {}

    @classmethod
    def _cls_repr(cls):
        return "Street: <class '{}.{}'>".format(cls.__module__, cls.__name__)

    @classmethod
    def get_lot_to_travel_to(cls):
        if cls is services.current_street():
            return
        import world.lot
        return world.lot.get_lot_id_from_instance_id(cls.travel_lot)

    @classmethod
    def has_conditional_layer(cls, conditional_layer):
        return conditional_layer in cls.valid_conditional_layers

    @classmethod
    def clear_caches(cls):
        Street.street_to_lot_id_to_zone_ids.clear()
        Street.ZONE_IDS_BY_STREET = None
Beispiel #12
0
class CollectionInteractionData:
    COLLECTION_COMBINING_TUNING = TunableMapping(
        description=
        '\n        Mapping of collectible id, to states that we allow for collectible\n        combining.\n        ',
        key_type=TunableEnumEntry(
            description=
            '\n            ID of the collectible that can be combined.\n            ',
            tunable_type=CollectionIdentifier,
            default=CollectionIdentifier.Unindentified),
        value_type=TunableTuple(
            description=
            '\n            Possible states that can be combined on a collectible.\n            Mapping of state values that can be combined to get a new state\n            ',
            states_to_combine=TunableList(
                description=
                '\n                Any states tuned here will be transfered from the combine \n                collectibles to the resulting object.\n                For example: Frogs will transfer their color and pattern \n                states.\n                ',
                tunable=ObjectState.TunableReference(
                    description=
                    '\n                    State that can be inherited by the new collectible.\n                    '
                )),
            combination_mapping=TunableList(
                description=
                '\n                Mapping of possible father-mother states to which new\n                state can they generate on the newly created collectible.\n                e.g.  If collectible A has green color state, and collectible\n                B has blue color states the resulting state can be a Green \n                color state.  This means the outcome of the interaction will\n                look for a collectible that has this resulting state value.\n                ',
                tunable=TunableTuple(
                    description=
                    '\n                    State combinations to create a new state on the \n                    result collectible.\n                    ',
                    father_state=ObjectStateValue.TunableReference(),
                    mother_state=ObjectStateValue.TunableReference(),
                    resulting_state=ObjectStateValue.TunableReference()))))
Beispiel #13
0
class UniversitySpecificSpawnPointTags(HasTunableSingletonFactory,
                                       AutoFactoryInit):
    FACTORY_TUNABLES = {
        'spawn_point_tags':
        TunableMapping(
            description=
            '\n            University specific classroom tags.\n            ',
            key_type=TunableReference(
                manager=services.get_instance_manager(Types.UNIVERSITY)),
            value_type=TunableSet(tunable=TunableEnumWithFilter(
                tunable_type=Tag,
                default=Tag.INVALID,
                filter_prefixes=('Spawn', )),
                                  minlength=1))
    }

    def get_tags(self, sim_info, interaction):
        degree_tracker = sim_info.degree_tracker
        if degree_tracker is None:
            logger.error(
                'Trying to get University Specific spawn point from sim {} with no degree tracker',
                sim_info)
            return EMPTY_SET
        university = degree_tracker.get_university()
        if university not in self.spawn_point_tags:
            return EMPTY_SET
        return self.spawn_point_tags[university]
Beispiel #14
0
class SeasonalContent(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'holidays':
        TunableMapping(key_type=TunableReference(
            description=
            '\n                Drama node to be scheduled for this holiday.\n                ',
            manager=services.get_instance_manager(
                sims4.resources.Types.HOLIDAY_DEFINITION),
            pack_safe=True),
                       value_type=TunableList(
                           tunable=DayOfSeason.TunableFactory())),
        'segments':
        TunableTuple(
            early_season_length=TunableTimeSpan(
                description=
                '\n                Early season length, in days.\n                ',
                default_days=2,
                locked_args={
                    'hours': 0,
                    'minutes': 0
                }),
            late_season_length=TunableTimeSpan(
                description=
                '\n                Late season length, in days.\n                ',
                default_days=2,
                locked_args={
                    'hours': 0,
                    'minutes': 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 InteractionCancelCompatibility:
    __qualname__ = 'InteractionCancelCompatibility'
    INTERACTION_CANCEL_COMPATIBILITY = TunableMapping(description='\n        A mapping between cancel reasons and affordance filters.  When a reason\n        is requested it runs the interaction though the affordance filter that\n        is requested along with all affordance filters in the hierarchy above\n        it.\n        \n        For example, the wedding will ensure the the interaction matches the\n        wedding, fire, and death reasons.\n        \n        The hierarchy of reasons is defined within python.  GPE support will be\n        needed to change or add new values to the hierarchy of reasons.\n        ', key_type=TunableEnumEntry(description='\n            An interaction canceling reason.\n            ', tunable_type=InteractionCancelReason, default=InteractionCancelReason.DEATH), value_type=TunableAffordanceFilterSnippet(description='\n            An affordance filter that defines which interactions are able to\n            be canceled.  If the interaction is not compatible with the\n            affordance filter then it will be canceled.\n            ', needs_tuning=True))

    @classmethod
    def can_cancel_interaction_for_reason(cls, interaction, reason):
        while reason is not None:
            interaction_compatibility_filter = cls.INTERACTION_CANCEL_COMPATIBILITY.get(reason)
            if interaction_compatibility_filter is None:
                logger.warn('InteractionCancelReason {} not found within the INTERACTION_CANCEL_HIARCHY tuning skipping to next reason.', reason)
            elif interaction_compatibility_filter(interaction):
                return False
            reason = InteractionCancelReason.get_next_reason(reason)
        return True

    @classmethod
    def cancel_interactions_for_reason(cls, sim, reason, finishing_type, cancel_reason_msg):
        sim_interactions = sim.get_all_running_and_queued_interactions()
        for interaction in sim_interactions:
            while cls.check_if_source_should_be_canceled(interaction.context) and cls.can_cancel_interaction_for_reason(interaction.affordance, reason):
                interaction.cancel(finishing_type, cancel_reason_msg=cancel_reason_msg)

    @classmethod
    def check_if_source_should_be_canceled(cls, context):
        if context.source is not InteractionSource.PIE_MENU and context.source is not InteractionSource.AUTONOMY and context.source is not InteractionSource.SCRIPT_WITH_USER_INTENT:
            return False
        return True
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)
class TunableSituationJobAndRoles(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'jobs_and_roles':
        TunableMapping(
            description=
            "\n            A mapping between a situation's jobs and default role states.\n            ",
            key_type=TunableReference(
                description=
                '\n                A job created for this situation.\n                ',
                manager=services.situation_job_manager()),
            key_name='Situation Job',
            value_type=TunableTuple(
                number_of_sims_to_find=TunableRange(
                    description=
                    '\n                    The number of sims to find for this job.\n                    ',
                    tunable_type=int,
                    default=1,
                    minimum=1),
                role=TunableReference(
                    description=
                    '\n                    The role state that the sim of this job starts the situation with.\n                    ',
                    manager=services.get_instance_manager(
                        sims4.resources.Types.ROLE_STATE))),
            value_name='Role State Info')
    }
class PackSpecificTuning:
    VENUE_PACK_TUNING = TunableMapping(
        description=
        "\n        Venue tuning that is needed by UI when that venue's pack is not installed.\n        ",
        key_name='venue_id',
        key_type=TunableReference(
            description=
            '\n            Reference to the venue that this data represents\n            ',
            manager=services.get_instance_manager(sims4.resources.Types.VENUE),
            pack_safe=True),
        value_name='data',
        value_type=TunableTuple(
            description=
            "\n            Venue data that is shown in the UI when this venue's pack is not installed.\n            ",
            gallery_download_venue=OptionalTunable(
                description=
                '\n                If tuned, the tuned venue tuning will be substituted if this\n                venue is downloaded from the gallery by a player who is not\n                entitled to it. The default behavior is to substitute the\n                generic venue. This tuned venue will also determine download\n                compatibility (for instance, only residential venues can be \n                downloaded to owned residential venues).\n                ',
                tunable=TunableReference(manager=services.get_instance_manager(
                    sims4.resources.Types.VENUE))),
            venue_name=TunableLocalizedStringFactory(
                description=
                '\n                Name that will be displayed for the venue when the pack containing \n                that venue is not installed\n                '
            ),
            venue_flags=TunableEnumFlags(
                description=
                '\n                Venue flags used to mark a venue with specific properties.\n                ',
                enum_type=VenueFlags,
                allow_no_flags=True,
                default=VenueFlags.NONE),
            export_class_name='VenueDataTuple'),
        tuple_name='VenuePackTuning',
        export_modes=ExportModes.All,
        verify_tunable_callback=verify_venue_tuning)
class TempleRoomData(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'gate':
        TunableSet(
            description=
            '\n            A set of states in which the gate in this room can potentially\n            start.\n            ',
            tunable=TunableReference(
                description=
                '\n                A potential starting state for the gate in this room.\n                ',
                manager=services.get_instance_manager(
                    sims4.resources.Types.OBJECT_STATE),
                class_restrictions=('ObjectStateValue', ))),
        'traps':
        TunableMapping(
            description=
            '\n            A mapping of trap objects to the interactions that can be used in\n            the pool potential of "trigger" interaction. A trap object will be\n            chosen at random from this mapping and placed at each placeholder\n            trap in this room. Once all trap objects have been chosen and placed\n            for a room, all of the mapped interactions will be collected and one\n            random interaction will be chosen as the "trigger" interaction.\n            ',
            key_name='Trap',
            key_type=TunableReference(
                description=
                '\n                A reference to the trap object.\n                ',
                manager=services.definition_manager()),
            value_name='Potential Trigger Interactions',
            value_type=TunableSet(
                description=
                '\n                A set of interactions that, if successfully completed on the\n                chosen trap object, will trigger the loot for the gate in this\n                room.\n                ',
                tunable=TunableReference(
                    description=
                    '\n                    One of the potential trigger interactions. This interaction\n                    also needs to be tuned on the object chosen for this trap.\n                    ',
                    manager=services.get_instance_manager(
                        sims4.resources.Types.INTERACTION),
                    class_restrictions=('SuperInteraction', ))))
    }
Beispiel #21
0
 def __init__(self, **kwargs):
     super().__init__(
         job_list=TunableMapping(
             description='A list of roles associated with the situation.',
             key_type=TunableReference(services.situation_job_manager(),
                                       description='Job reference'),
             value_type=TunableReference(
                 services.get_instance_manager(
                     sims4.resources.Types.ROLE_STATE),
                 description='Role the job will perform'),
             key_name='job',
             value_name='role'),
         exit_conditions=TunableList(
             TunableTuple(conditions=TunableList(
                 TunableSituationCondition(
                     description=
                     'A condition for a situation or single phase.'),
                 description=
                 'A list of conditions that all must be satisfied for the group to be considered satisfied.'
             )),
             description=
             'A list of condition groups of which if any are satisfied, the group is satisfied.'
         ),
         duration=TunableSimMinute(
             description=
             '\n                                                    How long the phase will last in sim minutes.\n                                                    0 means forever, which should be used on the last phase of the situation.\n                                                    ',
             default=60),
         **kwargs)
Beispiel #22
0
class AwarenessSourceRequest(HasTunableFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'awareness_sources':
        TunableMapping(
            description=
            "\n            A mapping of awareness channels and scores. The score is cumulative,\n            with all requests for the same channel contributing to an object's\n            awareness source score.\n            ",
            key_type=TunableEnumEntry(
                description=
                '\n                The channel to add an awareness score to.\n                ',
                tunable_type=AwarenessChannel,
                default=AwarenessChannel.PROXIMITY,
                invalid_enums=tuple(AwarenessChannel)),
            value_type=Tunable(
                description=
                '\n                The awareness score for this object, for the specified channel.\n                ',
                tunable_type=float,
                default=1))
    }

    def __init__(self, target, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._target = target

    def start(self, *_, **__):
        self._target.add_awareness_scores(self.awareness_sources)

    def stop(self, *_, **__):
        self._target.remove_awareness_scores(self.awareness_sources)
class CommonSituationState(SituationState, HasTunableFactory):
    FACTORY_TUNABLES = {
        'job_and_role_changes':
        TunableMapping(
            description=
            '\n                A mapping between situation jobs and role states that defines\n                what role states we want to switch to for sims on which jobs\n                when this situation state is entered.\n                ',
            key_type=TunableReference(
                description=
                "\n                    A reference to a SituationJob that we will use to change\n                    sim's role state.\n                    ",
                manager=services.situation_job_manager()),
            key_name='Situation Job',
            value_type=TunableReference(
                description=
                '\n                    The role state that we will switch sims of the linked job\n                    into.\n                    ',
                manager=services.get_instance_manager(
                    sims4.resources.Types.ROLE_STATE)),
            value_name='Role State'),
        'allow_join_situation':
        Tunable(
            description=
            '\n                Whether the situation is allowed to join at this state.\n                ',
            tunable_type=bool,
            default=True),
        'time_out':
        OptionalTunable(
            description=
            '\n                How long this state will last before time expired. Please talk to the GPE who implemented the specific\n                situation to see what the state will do on time expired.\n                ',
            tunable=TunableSimMinute(default=15, minimum=1))
    }

    def __init__(self, job_and_role_changes, allow_join_situation, time_out):
        super().__init__()
        self._job_and_role_changes = job_and_role_changes
        self._allow_join_situation = allow_join_situation
        self._time_out = time_out
        self._time_out_string = '' if self._time_out is None else '{}_TIMEOUT'.format(
            self.__class__.__name__)

    def on_activate(self, reader=None):
        super().on_activate(reader)
        self._set_job_role_state()
        if self._time_out is not None:
            self._create_or_load_alarm(self._time_out_string,
                                       self._time_out,
                                       lambda _: self.timer_expired(),
                                       should_persist=True)

    def _set_job_role_state(self):
        for (job, role_state) in self._job_and_role_changes.items():
            self.owner._set_job_role_state(job, role_state)

    def get_all_job_and_role_states(self):
        return self._job_and_role_changes.items()

    def allow_join_situation(self):
        return self._allow_join_situation

    def timer_expired(self):
        pass
Beispiel #24
0
class MixerActorMixin:
    INSTANCE_TUNABLES = {'actor_mixers': TunableMapping(description='\n            Mixers this adds to an associated actor object. (When targeting\n            something else.)\n            ', key_type=TunableReference(description='\n                The super affordance these mixers are associated with.\n                ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION), class_restrictions=('SuperInteraction',), pack_safe=True), value_type=TunableSet(description='\n                Set of mixer affordances associated with the super affordance.\n                ', tunable=TunableReference(description='\n                    Linked mixer affordance.\n                    ', manager=services.get_instance_manager(sims4.resources.Types.INTERACTION), category='asm', class_restrictions=('MixerInteraction',), pack_safe=True)))}

    @flexmethod
    def get_actor_mixers(cls, inst, super_interaction):
        inst_or_cls = inst if inst is not None else cls
        mixers = inst_or_cls.actor_mixers.get(super_interaction, [])
        return mixers
Beispiel #25
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
Beispiel #26
0
class SituationCategory:
    CATEGORIES = TunableMapping(
        description='\n\t\tMapping from Uid to Name\n        ',
        key_type=TunableEnumEntry(
            description='\n            The Situation Category.\n            ',
            tunable_type=SituationCategoryUid,
            default=SituationCategoryUid.DEFAULT),
        value_type=TunableLocalizedString(
            description='\n            The Category Name\n            '))
Beispiel #27
0
class GlobalLotTuningAndCleanup:
    OBJECT_COUNT_TUNING = TunableMapping(description='\n        Mapping between statistic and a set of tests that are run over the\n        objects on the lot on save.  The value of the statistic is set to the\n        number of objects that pass the tests.\n        ', key_type=TunableReference(description='\n            The statistic on the lot that will be set the value of the number\n            of objects that pass the test set that it is mapped to.\n            ', manager=services.get_instance_manager(sims4.resources.Types.STATISTIC), pack_safe=True), value_type=TunableTestSet(description='\n            Test set that will be run on all objects on the lot to determine\n            what the value of the key statistic should be set to.\n            '))
    SET_STATISTIC_TUNING = TunableList(description='\n        A list of statistics and values that they will be set to on the lot\n        while saving it when the lot was running.\n        \n        These values are set before counting by tests on objects.\n        ', tunable=TunableTuple(statistic=TunableReference(description='\n                The statistic that will have its value set.\n                ', manager=services.get_instance_manager(sims4.resources.Types.STATISTIC)), amount=Tunable(description='\n                The value that the statistic will be set to.\n                ', tunable_type=float, default=0.0)))
    OBJECT_CLEANUP_TUNING = TunableList(description='\n        A list of actions to take when spinning up a zone in order to fix it\n        up based on statistic values that the lot has.\n        ', tunable=TunableTuple(count=TunableVariant(all_items=AllItems(), statistic_value=StatisticValue(), statistic_difference=StatisticDifference(), default='all_items', description='\n                    The maximum number of items that will have the action run\n                    on them. \n                '), possible_actions=TunableList(description='\n                The different possible actions that can be taken on objects on\n                the lot if tests pass.\n                ', tunable=TunableTuple(actions=TunableList(description='\n                        A group of actions to be taken on the object.\n                        ', tunable=TunableVariant(set_state=SetState(), destroy_object=DestroyObject(), statistic_change=StatisticChange(), cleanup_vehicle=CleanupVehicle(), default='set_state', description='\n                                The actual action that will be performed on the\n                                object if test passes.\n                            ')), tests=TunableTestSet(description='\n                        Tests that if they pass the object will be under\n                        consideration for this action being done on them.\n                        ')))))
    objects_to_destroy = None
    _count_tuning_optimizer = None

    @classmethod
    def _get_stat_count_optimizer(cls):
        if cls._count_tuning_optimizer is None:
            cls._count_tuning_optimizer = ObjectCountTuningOptimizer(cls.OBJECT_COUNT_TUNING)
        return cls._count_tuning_optimizer

    @classmethod
    def calculate_object_quantity_statistic_values(cls, lot):
        for set_statatistic in cls.SET_STATISTIC_TUNING:
            lot.set_stat_value(set_statatistic.statistic, set_statatistic.amount)
        new_statistic_values = collections.defaultdict(int)
        stat_counter = cls._get_stat_count_optimizer()
        for obj in services.object_manager().values():
            if obj.is_sim:
                continue
            if not obj.is_on_active_lot():
                continue
            stat_counter.increment_statistics(obj, new_statistic_values)
        for (statistic, value) in new_statistic_values.items():
            lot.set_stat_value(statistic, value)

    @classmethod
    def cleanup_objects(cls, lot=None):
        if lot is None:
            logger.error('Lot is None when trying to run lot cleanup.', owner='jjacobson')
            return
        cls.objects_to_destroy = set()
        for cleanup in GlobalLotTuningAndCleanup.OBJECT_CLEANUP_TUNING:
            items_to_cleanup = cleanup.count(lot)
            if items_to_cleanup == 0:
                continue
            items_cleaned_up = 0
            for obj in services.object_manager().values():
                if items_cleaned_up >= items_to_cleanup:
                    break
                if obj.is_sim:
                    continue
                resolver = SingleObjectResolver(obj)
                run_action = False
                for possible_action in cleanup.possible_actions:
                    if possible_action.tests.run_tests(resolver):
                        for action in possible_action.actions:
                            action(obj, lot)
                            run_action = True
                if run_action:
                    items_cleaned_up += 1
        for obj in cls.objects_to_destroy:
            obj.destroy(source=lot, cause='Cleaning up the lot')
        cls.objects_to_destroy = None
Beispiel #28
0
class TunableStatAsmParam(HasTunableSingletonFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {
        'level_ranges':
        TunableMapping(
            description=
            '\n            The value mapping of the stat range to stat value or user value. If\n            use_user_value is True, the range should be user value, otherwise\n            stat value.\n            ',
            key_type=Tunable(
                description=
                "\n                The asm parameter for Sim's stat level.\n                ",
                tunable_type=str,
                default=None,
                source_query=SourceQueries.SwingEnumNamePattern.format(
                    'statLevel')),
            value_type=TunableInterval(
                description=
                '\n                Stat value fall into the range (inclusive).\n                ',
                tunable_type=float,
                default_lower=1,
                default_upper=1)),
        'asm_param_name':
        Tunable(description='\n            The asm param name.\n            ',
                tunable_type=str,
                default='statLevel'),
        'use_user_value':
        Tunable(
            description=
            '\n            Whether use the user value or stat value to decide the asm_param.\n            ',
            tunable_type=bool,
            default=True),
        'use_effective_skill_level':
        Tunable(
            description=
            '\n            If true, the effective skill level of the Sim will be used for \n            the asm_param.\n            ',
            tunable_type=bool,
            default=True),
        'always_apply':
        Tunable(
            description=
            '\n            If checked, this parameter is always applied on any ASM involving the\n            owning Sim.\n            ',
            tunable_type=bool,
            default=False)
    }

    def get_asm_param(self, stat):
        stat_value = stat.get_user_value(
        ) if self.use_user_value else stat.get_value()
        if stat.is_skill:
            if self.use_effective_skill_level:
                stat_value = stat.tracker.owner.get_effective_skill_level(stat)
        asm_param_value = None
        for (range_key, stat_range) in self.level_ranges.items():
            if stat_value >= stat_range.lower_bound:
                if stat_value <= stat_range.upper_bound:
                    asm_param_value = range_key
                    break
        return (self.asm_param_name, asm_param_value)
Beispiel #29
0
class EnvironmentScoreTuning:
    ENVIRONMENT_SCORE_BROADCASTER = BroadcasterEnvironmentScore.TunableReference(description='\n        The singleton broadcaster that groups all scoring objects. The\n        constraints on this broadcaster determine the constraint within which a\n        Sim is affected by environment score.\n        ')
    ENVIRONMENT_SCORE_MOODS = TunableMapping(description="\n        Tags on Objects correspond to a particular Mood.\n                \n        When an object is going to contribute to the environment score, put a\n        tag in it's catalog object, and make sure that tag points to a Mood\n        here.\n        ", key_type=TunableEnumEntry(description='\n            The Tag that corresponds to mood and environmental scoring data.\n            ', tunable_type=tag.Tag, default=tag.Tag.INVALID), value_type=Mood.TunableReference(description='\n            The mood that the Sim must be in for an object that emits this mood\n            to score. Corresponds to the mood_tag.\n            '), key_name='object_tag', value_name='mood')
    NEGATIVE_ENVIRONMENT_SCORING = Commodity.TunableReference(description='\n        Defines the ranges and corresponding buffs to apply for negative\n        environmental contribution.\n        \n        Be sure to tune min, max, and the different states. The convergence\n        value is what will remove the buff. Suggested to be 0.\n        ')
    POSITIVE_ENVIRONMENT_SCORING = Commodity.TunableReference(description='\n        Defines the ranges and corresponding buffs to apply for positive\n        environmental contribution.\n        \n        Be sure to tune min, max, and the different states. The convergence\n        value is what will remove the buff. Suggested to be 0.\n        ')
    BUILD_OBJECTS_ENVIRONMENT_SCORING = TunableTuple(description='\n        Defines the statistics which track the value of positive and negative\n        environmental contribution from build objects.\n        ', negative_environment_scoring=TunableReference(description='\n            Negative environmental statistic.\n            ', manager=services.get_instance_manager(Types.STATISTIC), class_restrictions=('Statistic',)), positive_environment_scoring=TunableReference(description='\n            Positive environmental statistic.\n            ', manager=services.get_instance_manager(Types.STATISTIC), class_restrictions=('Statistic',)))
    ENABLE_AFFORDANCE = TunableReference(description='\n        The interaction that will turn on Environment Score for a particular\n        object. This interaction should set a state on the object that will\n        have multipliers of 1 and adders of 0 for all moods.\n        ', manager=services.affordance_manager())
    DISABLE_AFFORDANCE = TunableReference(description='\n        The interaction that will turn off Environment Score for a particular\n        object. This interaction should set a state on the object that will\n        have multipliers of 0 and adders of 0 for all moods.\n        ', manager=services.affordance_manager())
    ENABLED_STATE_VALUE = ObjectStateValue.TunableReference(description='\n        A state value that indicates the object should be contributing\n        Environment Score.\n        ')
    DISABLED_STATE_VALUE = ObjectStateValue.TunableReference(description='\n        A state value that indicates the object should not be contributing\n        Environment Score.\n        ')
Beispiel #30
0
class SituationSimParticipantProviderMixin(HasTunableFactory, AutoFactoryInit):
    FACTORY_TUNABLES = {'provided_participant_type_to_job_map': TunableMapping(description='\n            Mapping from the liability provided type to the jobs it will search\n            for the participants in.\n            ', key_type=TunableEnumEntry(description='\n                Participant type that will be populated with the found Sims\n                ', tunable_type=ParticipantTypeSituationSims, default=ParticipantTypeSituationSims.SituationParticipants1), value_type=TunableList(description='\n                Situation sim providers allow the ability to search for Sims with specific\n                jobs that share a situation with the provided participant.\n                ', tunable=SituationSimProvider.TunableFactory()))}

    def get_participants(self, participant_type, resolver):
        if participant_type in self.provided_participant_type_to_job_map:
            participants = set()
            for provider in self.provided_participant_type_to_job_map[participant_type]:
                participants.update(provider.get_participants(resolver))
            return tuple(participants)
        return ()