Пример #1
0
 def mod_identity(self) -> CommonModIdentity:
     return self._mod_identity or ModInfo.get_identity()
Пример #2
0
    def run_with_sims(self,
                      sim_info_a: SimInfo,
                      sim_info_b: SimInfo,
                      on_completed: Callable[[bool],
                                             None] = CommonFunctionUtils.noop):
        relationship_track_id = self._determine_relationship_track(
            sim_info_a, sim_info_b)
        if relationship_track_id == -1:
            self.log.format_with_message(
                'No relationship track id found between Sims.',
                sim=sim_info_a,
                chosen_sim=sim_info_b)
            on_completed(False)
            return
        relationship_track = CommonResourceUtils.load_instance(
            Types.STATISTIC, relationship_track_id)
        if relationship_track is None:
            self.log.format_with_message('No relationship track found.',
                                         sim=sim_info_a,
                                         chosen_sim=sim_info_b)
            on_completed(False)
            return
        relationship_options = self._load_relationship_options(
            relationship_track)
        if not relationship_options:
            self.log.format_with_message('No relationship options found.',
                                         sim=sim_info_a,
                                         chosen_sim=sim_info_b)
            on_completed(False)
            return

        def _on_bit_chosen(_: Any, chosen_option: S4CMRelationshipOption):
            if _ is None or chosen_option is None:
                on_completed(False)
                return
            self.log.format_with_message(
                'Chose relationship bit.',
                sim=sim_info_a,
                chosen_sim=sim_info_b,
                chosen_option=chosen_option,
                required_minimum=chosen_option.required_minimum)
            CommonRelationshipUtils.add_relationship_bit(
                sim_info_a, sim_info_b, CommonRelationshipBitId.HAS_MET)
            CommonRelationshipUtils.set_relationship_level_of_sims(
                sim_info_a, sim_info_b, relationship_track_id,
                chosen_option.required_minimum)
            on_completed(True)

        option_dialog = CommonChooseButtonOptionDialog(
            ModInfo.get_identity(),
            S4CMSimControlMenuStringId.CHOOSE_LEVEL,
            0,
            include_previous_button=True,
            on_previous=lambda: on_completed(False),
            on_close=lambda: on_completed(False))
        for relationship_option in relationship_options:
            option_dialog.add_option(
                CommonDialogButtonOption(relationship_option,
                                         relationship_option,
                                         CommonDialogResponseOptionContext(
                                             relationship_option.display_name),
                                         on_chosen=_on_bit_chosen))

        if not option_dialog.has_options():
            on_completed(False)
            return

        option_dialog.show(sim_info=sim_info_a)
class CommonSimPregnancyUtils:
    """Utilities for manipulating the pregnancy status of Sims.

    """
    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def is_pregnant(sim_info: SimInfo) -> bool:
        """is_pregnant(sim_info)

        Determine if the specified Sim is pregnant.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim is pregnant. False, if not.
        :rtype: bool
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        return pregnancy_tracker.is_pregnant

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def start_pregnancy(sim_info: SimInfo, partner_sim_info: SimInfo) -> bool:
        """start_pregnancy(sim_info, partner_sim_info)

        Start a pregnancy between a Sim and a Partner Sim.

        :param sim_info: The Sim getting pregnant.
        :type sim_info: SimInfo
        :param partner_sim_info: The Sim that is getting the other Sim pregnant.
        :type partner_sim_info: SimInfo
        :return: True, if successful. False, if not.
        :rtype: bool
        """
        if not CommonHouseholdUtils.has_free_household_slots(sim_info):
            return False
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        pregnancy_tracker.start_pregnancy(sim_info, partner_sim_info)
        pregnancy_tracker.clear_pregnancy_visuals()
        CommonSimStatisticUtils.set_statistic_value(
            sim_info, CommonStatisticId.PREGNANCY, 1.0)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def clear_pregnancy(sim_info: SimInfo) -> bool:
        """clear_pregnancy(sim_info)

        Clear the pregnancy status of a Sim.

        :param sim_info: The Sim being cleared.
        :type sim_info: SimInfo
        :return: True, if successful. False, if not.
        :rtype: bool
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        sim_info.pregnancy_tracker.clear_pregnancy()
        CommonSimStatisticUtils.remove_statistic(sim_info,
                                                 CommonStatisticId.PREGNANCY)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def can_be_impregnated(sim_info: SimInfo) -> bool:
        """can_be_impregnated(sim_info)

        Determine if a Sim can be impregnated.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: True, if they can. False, if they cannot.
        :rtype: bool
        """
        from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils
        from sims4communitylib.enums.traits_enum import CommonTraitId
        if CommonSpeciesUtils.is_human(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info, CommonTraitId.
                    GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED):
                return False
            return CommonTraitUtils.has_trait(
                sim_info,
                CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED)
        elif CommonSpeciesUtils.is_pet(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)
        return False

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def can_impregnate(sim_info: SimInfo) -> bool:
        """can_impregnate(sim_info)

        Determine if a Sim can impregnate other sims.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: True, if they can. False, if they cannot.
        :rtype: bool
        """
        from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils
        from sims4communitylib.enums.traits_enum import CommonTraitId
        if CommonSpeciesUtils.is_human(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info,
                CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE)
        elif CommonSpeciesUtils.is_pet(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)
        return False

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def get_partner_of_pregnant_sim(sim_info: SimInfo) -> Union[SimInfo, None]:
        """get_partner_of_pregnant_sim(sim_info)

        Retrieve a SimInfo object of the Sim that impregnated the specified Sim.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The Sim that has impregnated the specified Sim or None if the Sim does not have a partner.
        :rtype: Union[SimInfo, None]
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return None
        return pregnancy_tracker.get_partner()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=0.0)
    def get_pregnancy_progress(sim_info: SimInfo) -> float:
        """get_pregnancy_progress(sim_info)

        Retrieve the pregnancy progress of a Sim.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The current progress of the pregnancy of a Sim.
        :rtype: float
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None or not CommonSimPregnancyUtils.is_pregnant(
                sim_info):
            return 0.0
        pregnancy_commodity_type = pregnancy_tracker.PREGNANCY_COMMODITY_MAP.get(
            CommonSpeciesUtils.get_species(sim_info))
        statistic_tracker = sim_info.get_tracker(pregnancy_commodity_type)
        pregnancy_commodity = statistic_tracker.get_statistic(
            pregnancy_commodity_type, add=False)
        if not pregnancy_commodity:
            return 0.0
        return pregnancy_commodity.get_value()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=0.0)
    def get_pregnancy_rate(sim_info: SimInfo) -> float:
        """get_pregnancy_rate(sim_info)

        Retrieve the rate at which pregnancy progresses.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The rate at which the pregnancy state of a Sim is progressing.
        :rtype: float
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return 0.0
        return pregnancy_tracker.PREGNANCY_RATE

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def _get_pregnancy_tracker(
            sim_info: SimInfo) -> Union[PregnancyTracker, None]:
        if sim_info is None:
            return None
        return sim_info.pregnancy_tracker
 def get_mod_identity(cls) -> CommonModIdentity:
     return ModInfo.get_identity()
class CommonChooseItemDialog:
    """CommonChooseItemDialog(\
        title_identifier,\
        description_identifier,\
        list_items,\
        title_tokens=(),\
        description_tokens=()\
    )

    Create a dialog that prompts the player to choose an item.

    .. warning:: Obsolete: Please use :class:`.CommonChooseObjectDialog` instead.
        Use to create a dialog that prompts the player to choose a single item from a list of items.

    .. note:: To see an example dialog, run the command :class:`s4clib_testing.show_choose_item_dialog` in the in-game console.

    .. highlight:: python
    .. code-block:: python

        def _common_testing_show_choose_item_dialog():

            def _item_chosen(chosen_item: str, result: CommonChooseItemResult):
                pass

            # LocalizedStrings within other LocalizedStrings
            title_tokens = (CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_SOME_TEXT_FOR_TESTING, text_color=CommonLocalizedStringColor.GREEN),)
            description_tokens = (CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_TEXT_WITH_SIM_FIRST_AND_LAST_NAME, tokens=(CommonSimUtils.get_active_sim_info(),), text_color=CommonLocalizedStringColor.BLUE),)
            from sims4communitylib.utils.common_icon_utils import CommonIconUtils
            options = [ObjectPickerRow(option_id=1, name=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_SOME_TEXT_FOR_TESTING),
                                       row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_ONE),
                                       row_tooltip=None,
                                       icon=CommonIconUtils.load_checked_square_icon(),
                                       tag='Value 1'),
                       ObjectPickerRow(option_id=2, name=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_SOME_TEXT_FOR_TESTING),
                                       row_description=CommonLocalizationUtils.create_localized_string(CommonStringId.TESTING_TEST_BUTTON_TWO),
                                       row_tooltip=None,
                                       icon=CommonIconUtils.load_arrow_navigate_into_icon(),
                                       tag='Value 2')]
            dialog = CommonChooseItemDialog(CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
                                            CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
                                            tuple(options),
                                            title_tokens=title_tokens,
                                            description_tokens=description_tokens)
            dialog.show(on_item_chosen=_item_chosen)

    :param title_identifier: A decimal identifier of the title text.
    :type title_identifier: Union[int, LocalizedString]
    :param description_identifier: A decimal identifier of the description text.
    :type description_identifier: Union[int, LocalizedString]
    :param list_items: The items to display in the dialog.
    :type list_items: Tuple[ObjectPickerRow]
    :param title_tokens: Tokens to format into the title.
    :type title_tokens: Tuple[Any], optional
    :param description_tokens: Tokens to format into the description.
    :type description_tokens: Tuple[Any], optional
    """
    def __init__(self,
                 title_identifier: Union[int, LocalizedString],
                 description_identifier: Union[int, LocalizedString],
                 list_items: Tuple[ObjectPickerRow],
                 title_tokens: Tuple[Any] = (),
                 description_tokens: Tuple[Any] = ()):
        self.title = CommonLocalizationUtils.create_localized_string(
            title_identifier, tokens=title_tokens)
        self.description = CommonLocalizationUtils.create_localized_string(
            description_identifier, tokens=description_tokens)
        self.list_items = list_items

    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name)
    def add_item(self, item: ObjectPickerRow):
        """add_item(item)

        Add a new item to choose from.

        :param item: The item to add.
        :type item: ObjectPickerRow
        """
        self.list_items += (item, )

    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name)
    def show(self,
             on_item_chosen: Callable[[Any, CommonChooseItemResult],
                                      Any] = CommonFunctionUtils.noop,
             picker_type: UiObjectPicker.
             UiObjectPickerObjectPickerType = UiObjectPicker.
             UiObjectPickerObjectPickerType.OBJECT):
        """show(\
            on_item_chosen=CommonFunctionUtils.noop,\
            picker_type=UiObjectPicker.UiObjectPickerObjectPickerType.OBJECT\
        )

        Show the dialog and invoke the callbacks upon the player selecting an item.

        :param on_item_chosen: Invoked upon the player choosing an item from the list.
        :type on_item_chosen: Callable[[Any, CommonChooseItemResult], Any], optional
        :param picker_type: Determines how the items appear in the dialog.
        :type picker_type: UiObjectPicker.UiObjectPickerObjectPickerType, optional
        """
        _dialog = self._create_dialog(picker_type=picker_type)
        if _dialog is None:
            return

        def _on_item_chosen(dialog: UiObjectPicker):
            if not dialog.accepted:
                return on_item_chosen(
                    None,
                    CommonChooseItemResult(
                        CommonChooseItemResult.DIALOG_CANCELLED))
            chosen_item = CommonDialogUtils.get_chosen_item(dialog)
            return on_item_chosen(
                chosen_item,
                CommonChooseItemResult(CommonChooseItemResult.ITEM_CHOSEN))

        for list_item in self.list_items:
            _dialog.add_row(list_item)

        _dialog.add_listener(_on_item_chosen)
        _dialog.show_dialog()

    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name,
                                             fallback_return=None)
    def _create_dialog(
        self,
        picker_type: UiObjectPicker.
        UiObjectPickerObjectPickerType = UiObjectPicker.
        UiObjectPickerObjectPickerType.OBJECT
    ) -> Union[UiObjectPicker, None]:
        return UiObjectPicker.TunableFactory().default(
            CommonSimUtils.get_active_sim_info(),
            text=lambda *_, **__: self.description,
            title=lambda *_, **__: self.title,
            min_selectable=1,
            max_selectable=1,
            picker_type=picker_type)
class CommonTraitUtils:
    """Utilities for manipulating Traits on Sims.

    """
    @staticmethod
    def is_special_npc(sim_info: SimInfo) -> bool:
        """is_special_npc(sim_info)

        Determine if a sim is a Special NPC.

        .. note::

            Special NPCs:

            - Hidden Event NPC
            - Grim Reaper
            - Scarecrow
            - Flower Bunny

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        traits = (
            CommonTraitId.HIDDEN_IS_EVENT_NPC_CHALLENGE,
            CommonTraitId.IS_GRIM_REAPER,
            CommonTraitId.SCARECROW,
            CommonTraitId.FLOWER_BUNNY
        )
        return CommonTraitUtils.has_trait(sim_info, *traits)

    @staticmethod
    def is_active(sim_info: SimInfo) -> bool:
        """is_active(sim_info)

        Determine if a Sim is active.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.ACTIVE)

    @staticmethod
    def is_aggressive_pet(sim_info: SimInfo) -> bool:
        """is_aggressive_pet(sim_info)

        Determine if a pet sim is Aggressive.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_AGGRESSIVE_DOG,
            CommonTraitId.PET_AGGRESSIVE_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_alluring(sim_info: SimInfo) -> bool:
        """is_alluring(sim_info)

        Determine if a sim is Alluring.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.ALLURING)

    @staticmethod
    def is_antiseptic(sim_info: SimInfo) -> bool:
        """is_antiseptic(sim_info)

        Determine if a sim is Antiseptic.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.ANTISEPTIC)

    @staticmethod
    def is_bro(sim_info: SimInfo) -> bool:
        """is_bro(sim_info)

        Determine if a sim is a Bro.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.BRO)

    @staticmethod
    def is_carefree(sim_info: SimInfo) -> bool:
        """is_carefree(sim_info)

        Determine if a sim is Care Free.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.CAREFREE)

    @staticmethod
    def is_cat_lover(sim_info: SimInfo) -> bool:
        """is_cat_lover(sim_info)

        Determine if a sim is a Cat Lover.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.CAT_LOVER)

    @staticmethod
    def is_dog_lover(sim_info: SimInfo) -> bool:
        """is_dog_lover(sim_info)

        Determine if a sim is a Dog Lover.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.DOG_LOVER)

    @staticmethod
    def is_clumsy(sim_info: SimInfo) -> bool:
        """is_clumsy(sim_info)

        Determine if a sim is Clumsy.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.CLUMSY)

    @staticmethod
    def is_dastardly(sim_info: SimInfo) -> bool:
        """is_dastardly(sim_info)

        Determine if a sim is Dastardly.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.DASTARDLY)

    @staticmethod
    def is_criminal(sim_info: SimInfo) -> bool:
        """is_criminal(sim_info)

        Determine if a sim is a Criminal.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.DETECTIVE_CAREER_CRIMINAL,
            CommonTraitId.DETECTIVE_CAREER_POLICE_STATION_CRIMINAL_NPC
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_evil(sim_info: SimInfo) -> bool:
        """is_evil(sim_info)

        Determine if a sim is Evil.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.EVIL,
            CommonTraitId.EVIL_BEGONIA_SCENT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_fertile(sim_info: SimInfo) -> bool:
        """is_fertile(sim_info)

        Determine if a sim is Fertile.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.FERTILE)

    @staticmethod
    def is_friendly_pet(sim_info: SimInfo) -> bool:
        """is_friendly_pet(sim_info)

        Determine if a pet sim is Friendly.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_FRIENDLY_DOG,
            CommonTraitId.PET_FRIENDLY_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_geek(sim_info: SimInfo) -> bool:
        """is_geek(sim_info)

        Determine if a Sim is a geek.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GEEK)

    @staticmethod
    def is_genius(sim_info: SimInfo) -> bool:
        """is_genius(sim_info)

        Determine if a sim is a Genius.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENIUS)

    @staticmethod
    def is_good(sim_info: SimInfo) -> bool:
        """is_good(sim_info)

        Determine if a sim is Good.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GOOD)

    @staticmethod
    def is_glutton(sim_info: SimInfo) -> bool:
        """is_glutton(sim_info)

        Determine if a sim is a Glutton.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.is_glutton_human(sim_info) or CommonTraitUtils.is_glutton_pet(sim_info)

    @staticmethod
    def is_glutton_human(sim_info: SimInfo) -> bool:
        """is_glutton_human(sim_info)

        Determine if a non pet sim is a Glutton

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GLUTTON)

    @staticmethod
    def is_glutton_pet(sim_info: SimInfo) -> bool:
        """is_glutton_pet(sim_info)

        Determine if a pet sim is a Glutton.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_GLUTTON_DOG,
            CommonTraitId.PET_GLUTTON_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_gregarious(sim_info: SimInfo) -> bool:
        """is_gregarious(sim_info)

        Determine if a sim is Gregarious.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GREGARIOUS)

    @staticmethod
    def is_hot_headed(sim_info: SimInfo) -> bool:
        """is_hot_headed(sim_info)

        Determine if a sim is Hot Headed.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.HOT_HEADED)

    @staticmethod
    def is_hunter_pet(sim_info: SimInfo) -> bool:
        """is_hunter_pet(sim_info)

        Determine if a pet sim is a Hunter.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_HUNTER_DOG,
            CommonTraitId.PET_HUNTER_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_incredibly_friendly(sim_info: SimInfo) -> bool:
        """is_incredibly_friendly(sim_info)

        Determine if a sim is Incredibly Friendly.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.INCREDIBLY_FRIENDLY)

    @staticmethod
    def is_insane(sim_info: SimInfo) -> bool:
        """is_insane(sim_info)

        Determine if a sim is Insane.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.INSANE)

    @staticmethod
    def is_insider(sim_info: SimInfo) -> bool:
        """is_insider(sim_info)

        Determine if a sim is an Insider.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.INSIDER)

    @staticmethod
    def is_loyal_pet(sim_info: SimInfo) -> bool:
        """is_loyal_pet(sim_info)

        Determine if a pet sim is Loyal.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_LOYAL_DOG,
            CommonTraitId.PET_LOYAL_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_mean(sim_info: SimInfo) -> bool:
        """is_mean(sim_info)

        Determine if a sim is Mean.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.MEAN)

    @staticmethod
    def is_mentor(sim_info: SimInfo) -> bool:
        """is_mentor(sim_info)

        Determine if a sim is a Mentor.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.MENTOR)

    @staticmethod
    def is_morning_person(sim_info: SimInfo) -> bool:
        """is_morning_person(sim_info)

        Determine if a sim is a Morning Person.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.MORNING_PERSON)

    @staticmethod
    def is_naughty_pet(sim_info: SimInfo) -> bool:
        """is_naughty_pet(sim_info)

        Determine if a pet sim is Naughty.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_NAUGHTY_DOG,
            CommonTraitId.PET_NAUGHTY_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_neat(sim_info: SimInfo) -> bool:
        """is_neat(sim_info)

        Determine if a Sim is neat.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.NEAT)

    @staticmethod
    def is_night_owl(sim_info: SimInfo) -> bool:
        """is_night_owl(sim_info)

        Determine if a sim is a Night Owl.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.NIGHT_OWL,
            CommonTraitId.NIGHT_OWL_CRYSTAL_HELMET
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_lazy(sim_info: SimInfo) -> bool:
        """is_lazy(sim_info)

        Determine if a sim is Lazy.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.LAZY)

    @staticmethod
    def is_loner(sim_info: SimInfo) -> bool:
        """is_loner(sim_info)

        Determine if a sim is a Loner.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.LONER)

    @staticmethod
    def is_love_guru(sim_info: SimInfo) -> bool:
        """is_love_guru(sim_info)

        Determine if a sim is a Love Guru.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.LOVE_GURU)

    @staticmethod
    def is_self_absorbed(sim_info: SimInfo) -> bool:
        """is_self_absorbed(sim_info)

        Determine if a sim is Self Absorbed.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SELF_ABSORBED)

    @staticmethod
    def is_self_assured(sim_info: SimInfo) -> bool:
        """is_self_assured(sim_info)

        Determine if a sim is Self Assured.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SELF_ASSURED)

    @staticmethod
    def is_service_sim(sim_info: SimInfo) -> bool:
        """is_service_sim(sim_info)

        Determine if a sim is a service sim.

        ..warning:: Obsolete: Use :func:`~is_service_sim` in :class:`.CommonSimTypeUtils` instead.

        """
        from sims4communitylib.utils.sims.common_sim_type_utils import CommonSimTypeUtils
        return CommonSimTypeUtils.is_service_sim(sim_info)

    @staticmethod
    def is_shameless(sim_info: SimInfo) -> bool:
        """is_shameless(sim_info)

        Determine if a sim is Shameless.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SHAMELESS)

    @staticmethod
    def is_sincere(sim_info: SimInfo) -> bool:
        """is_sincere(sim_info)

        Determine if a sim is Sincere.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SINCERE)

    @staticmethod
    def is_skittish_pet(sim_info: SimInfo) -> bool:
        """is_skittish_pet(sim_info)

        Determine if a pet sim is Skittish.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        trait_ids = (
            CommonTraitId.PET_SKITTISH_DOG,
            CommonTraitId.PET_SKITTISH_CAT
        )
        return CommonTraitUtils.has_trait(sim_info, *trait_ids)

    @staticmethod
    def is_slob(sim_info: SimInfo) -> bool:
        """is_slob(sim_info)

        Determine if a sim is a Slob.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SLOB)

    @staticmethod
    def is_snob(sim_info: SimInfo) -> bool:
        """is_snob(sim_info)

        Determine if a sim is a Snob.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SNOB)

    @staticmethod
    def is_squeamish(sim_info: SimInfo) -> bool:
        """is_squeamish(sim_info)

        Determine if a sim is Squeamish.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SQUEAMISH)

    @staticmethod
    def is_survivalist(sim_info: SimInfo) -> bool:
        """is_survivalist(sim_info)

        Determine if a sim is a Survivalist.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.SURVIVALIST)

    @staticmethod
    def is_unflirty(sim_info: SimInfo) -> bool:
        """is_unflirty(sim_info)

        Determine if a sim is Unflirty.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim has the Trait. False, if the Sim does not have the Trait.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.UNFLIRTY)

    @staticmethod
    def hates_children(sim_info: SimInfo) -> bool:
        """hates_children(sim_info)

        Determine if a sim Hates Children.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.HATES_CHILDREN)

    @staticmethod
    def has_animal_attraction(sim_info: SimInfo) -> bool:
        """has_animal_attraction(sim_info)

        Determine if a sim has an Animal Attraction.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.ANIMAL_ATTRACTION)

    @staticmethod
    def has_animal_whisperer(sim_info: SimInfo) -> bool:
        """has_animal_whisperer(sim_info)

        Determine if a sim is an Animal Whisperer.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.ANIMAL_WHISPERER)

    @staticmethod
    def has_challenge_kindness_ambassador(sim_info: SimInfo) -> bool:
        """has_challenge_kindness_ambassador(sim_info)

        Determine if a sim has Challenged the Kindness Ambassador.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.CHALLENGE_KINDNESS_AMBASSADOR)

    @staticmethod
    def has_commitment_issues(sim_info: SimInfo) -> bool:
        """has_commitment_issues(sim_info)

        Determine if a sim has Commitment Issues.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.COMMITMENT_ISSUES)

    @staticmethod
    def has_masculine_frame(sim_info: SimInfo) -> bool:
        """has_masculine_frame(sim_info)

        Determine if a sim has a Masculine Body Frame.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_MASCULINE)

    @staticmethod
    def has_feminine_frame(sim_info: SimInfo) -> bool:
        """has_feminine_frame(sim_info)

        Determine if a sim has a Feminine Body Frame.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_FRAME_FEMININE)

    @staticmethod
    def prefers_menswear(sim_info: SimInfo) -> bool:
        """prefers_menswear(sim_info)

        Determine if a sim prefers Mens Clothing.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_MENS_WEAR)

    @staticmethod
    def prefers_womenswear(sim_info: SimInfo) -> bool:
        """prefers_womenswear(sim_info)

        Determine if a sim prefers Womens Clothing.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim does. False, if the Sim does not.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_CLOTHING_WOMENS_WEAR)

    @staticmethod
    def can_impregnate(sim_info: SimInfo) -> bool:
        """can_impregnate(sim_info)

        Determine if a sim Can Impregnate.

        .. note:: Use :func:`~can_reproduce` for Pet Sims.
        .. note:: This will check for a sim to not also have the GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can impregnate other Sims. False, if the Sim can not impregnate other Sims.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE)

    @staticmethod
    def can_not_impregnate(sim_info: SimInfo) -> bool:
        """can_not_impregnate(sim_info)

        Determine if a sim Can Not Impregnate.

        .. note:: Use :func:`~can_not_reproduce` for Pet Sims.
        .. note:: This will check for a sim to not also have the GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can not impregnate other Sims. False, if the Sim can impregnate other Sims.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE)

    @staticmethod
    def can_be_impregnated(sim_info: SimInfo) -> bool:
        """can_be_impregnated(sim_info)

        Determine if a sim Can Be Impregnated.

        .. note:: Use :func:`~can_reproduce` for Pet Sims.
        .. note:: Will return False if the sim has the GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can be impregnated. False, if the Sim can not be impregnated.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED)

    @staticmethod
    def can_not_be_impregnated(sim_info: SimInfo) -> bool:
        """can_not_be_impregnated(sim_info)

        Determine if a sim Can Not Be Impregnated.

        .. note:: Use :func:`~can_not_reproduce` for Pet Sims.
        .. note:: Will return False if the sim has the GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can not be impregnated. False, if the Sim can be impregnated.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED)

    @staticmethod
    def can_create_pregnancy(sim_info: SimInfo) -> bool:
        """can_create_pregnancy(sim_info)

        Determine if a sim can either impregnate or be impregnated.

        .. note:: Will return False if the sim can both impregnate and not impregnate\
            or if the sim can both be impregnated and not be impregnated.

        .. note:: A Sim can impregnate when they can either impregnate other Sims or can be impregnated by other Sims.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can create pregnancies. False, if the Sim can not create pregnancies.
        :rtype: bool
        """
        return CommonTraitUtils.can_impregnate(sim_info) or CommonTraitUtils.can_be_impregnated(sim_info)

    @staticmethod
    def can_reproduce(sim_info: SimInfo) -> bool:
        """can_reproduce(sim_info)

        Determine if a pet sim can reproduce.

        .. note:: Use :func:`~can_impregnate` and :func:`~can_be_impregnated` for Human Sims.
        .. note:: Will return False if the pet sim has the PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can reproduce. False, if the Sim can not reproduce.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE)

    @staticmethod
    def can_not_reproduce(sim_info: SimInfo) -> bool:
        """can_not_reproduce(sim_info)

        Determine if a pet sim can reproduce.

        ..note:: Use :func:`~can_not_impregnate` and :func:`~can_not_be_impregnated` for Human Sims.
        .. note:: Will return False if the pet sim has the PREGNANCY_OPTIONS_PET_CAN_REPRODUCE trait.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim can not reproduce. False, if the Sim can reproduce.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE)\
               and not CommonTraitUtils.has_trait(sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)

    @staticmethod
    def uses_toilet_standing(sim_info: SimInfo) -> bool:
        """uses_toilet_standing(sim_info)

        Determine if a sim uses the toilet while standing.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim uses toilets while standing. False, if the Sim does not use toilets while standing.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_TOILET_STANDING)

    @staticmethod
    def uses_toilet_sitting(sim_info: SimInfo) -> bool:
        """uses_toilet_sitting(sim_info)

        Determine if a sim uses the toilet while sitting.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim uses toilets while sitting. False, if the Sim does not use toilets while sitting.
        :rtype: bool
        """
        return CommonTraitUtils.has_trait(sim_info, CommonTraitId.GENDER_OPTIONS_TOILET_SITTING)

    @staticmethod
    def has_trait(sim_info: SimInfo, *trait_ids: int) -> bool:
        """has_trait(sim_info, *trait_ids)

        Determine if a sim has any of the specified traits.

        :param sim_info: The sim to check.
        :type sim_info: SimInfo
        :param trait_ids: An iterable of identifiers of Traits.
        :type trait_ids: int
        :return: True, if the sim has any of the specified traits. False, if not.
        :rtype: bool
        """
        if not trait_ids:
            return False
        sim_traits = CommonTraitUtils.get_traits(sim_info)
        for trait in sim_traits:
            trait_id = getattr(trait, 'guid64', None)
            if trait_id in trait_ids:
                return True
        return False

    @staticmethod
    def get_trait_ids(sim_info: SimInfo) -> List[int]:
        """get_trait_ids(sim_info)

        Retrieve decimal identifiers for all Traits of a sim.

        :param sim_info: The sim to check.
        :type sim_info: SimInfo
        :return: A collection of Trait identifiers on a Sim.
        :rtype: List[int]
        """
        trait_ids = []
        for trait in CommonTraitUtils.get_traits(sim_info):
            trait_id = CommonTraitUtils.get_trait_id(trait)
            if trait_id is None:
                continue
            trait_ids.append(trait_id)
        return trait_ids

    @staticmethod
    def get_traits(sim_info: SimInfo) -> List[Trait]:
        """get_traits(sim_info)

        Retrieve all Traits of a sim.

        :param sim_info: The sim to check.
        :type sim_info: SimInfo
        :return: A collection of Traits on a Sim.
        :rtype: List[int]
        """
        if not hasattr(sim_info, 'get_traits'):
            return list()
        return list(sim_info.get_traits())

    @staticmethod
    def get_trait_name(trait: Trait) -> Union[str, None]:
        """get_trait_name(trait)

        Retrieve the Name of a Trait.

        :param trait: An instance of a Trait.
        :type trait: Trait
        :return: The name of a Trait or None if a problem occurs.
        :rtype: Union[str, None]
        """
        if trait is None:
            return None
        # noinspection PyBroadException
        try:
            return trait.__name__ or ''
        except:
            return ''

    @staticmethod
    def get_trait_names(traits: Iterator[Trait]) -> Tuple[str]:
        """get_trait_names(traits)

        Retrieve the Names of a collection of Trait.

        :param traits: A collection of Trait instances.
        :type traits: Iterator[Trait]
        :return: A collection of names for all specified Traits.
        :rtype: Tuple[str]
        """
        if traits is None or not traits:
            return tuple()
        names: List[str] = []
        for trait in traits:
            # noinspection PyBroadException
            try:
                name = CommonTraitUtils.get_trait_name(trait)
                if not name:
                    continue
            except:
                continue
            names.append(name)
        return tuple(names)

    @staticmethod
    def get_equipped_traits(sim_info: SimInfo) -> List[Trait]:
        """get_equipped_traits(sim_info)

        Retrieve Sims currently equipped traits.

        .. note:: The main use of this function is to check Occult Types.

        :param sim_info: An instance of a Sim.
        :type sim_info: SimInfo
        :return: A collection of equipped Traits on a Sim.
        :rtype: List[int]
        """
        if not hasattr(sim_info, 'trait_tracker') or not hasattr(sim_info.trait_tracker, 'equipped_traits'):
            return list()
        return list(sim_info.trait_tracker.equipped_traits)

    @staticmethod
    def add_trait(sim_info: SimInfo, *trait_ids: int) -> bool:
        """add_trait(sim_info, *trait_ids)

        Add the specified traits to a Sim.

        :param sim_info: The Sim to add the specified traits to.
        :type sim_info: SimInfo
        :param trait_ids: An iterable of Trait identifiers of traits being added.
        :type trait_ids: int
        :return: True, if all specified traits were successfully added to the Sim. False, if not.
        :rtype: bool
        """
        success = True
        for trait_id in trait_ids:
            trait_instance = CommonTraitUtils._load_trait_instance(trait_id)
            if trait_instance is None:
                continue
            if not sim_info.add_trait(trait_instance):
                success = False
        return success

    @staticmethod
    def remove_trait(sim_info: SimInfo, *trait_ids: int) -> bool:
        """remove_trait(sim_info, *trait_ids)

        Remove the specified traits from a Sim.

        :param sim_info: The Sim to remove the specified traits from.
        :type sim_info: SimInfo
        :param trait_ids: The decimal identifier of the trait being removed.
        :type trait_ids: int
        :return: True, if all specified traits were successfully removed from the Sim. False, if not.
        :rtype: bool
        """
        success = True
        for trait_id in trait_ids:
            trait_instance = CommonTraitUtils._load_trait_instance(trait_id)
            if trait_instance is None:
                continue
            if not sim_info.remove_trait(trait_instance):
                success = False
        return success

    @staticmethod
    def swap_traits(sim_info: SimInfo, trait_id_one: int, trait_id_two: int) -> bool:
        """swap_traits(sim_info, trait_id_one, trait_id_two)

        Remove one trait and add another to a Sim.

        .. note:: If `trait_id_one` exists on the Sim, it will be removed and `trait_id_two` will be added.
        .. note:: If `trait_id_two` exists on the Sim, it will be removed and `trait_id_one` will be added.

        :param sim_info: The Sim to remove the specified traits from.
        :type sim_info: SimInfo
        :param trait_id_one: The first trait to remove/add
        :type trait_id_one: int
        :param trait_id_two: The second trait to remove/add
        :type trait_id_two: int
        :return: True, if the Traits were swapped successfully. False, if neither Trait exists on a Sim or the traits were not swapped successfully.
        :rtype: bool
        """
        # Has Trait One
        if CommonTraitUtils.has_trait(sim_info, trait_id_one):
            CommonTraitUtils.remove_trait(sim_info, trait_id_one)
            if not CommonTraitUtils.has_trait(sim_info, trait_id_two):
                CommonTraitUtils.add_trait(sim_info, trait_id_two)
            return True
        # Has Trait Two
        elif CommonTraitUtils.has_trait(sim_info, trait_id_two):
            CommonTraitUtils.remove_trait(sim_info, trait_id_two)
            if not CommonTraitUtils.has_trait(sim_info, trait_id_one):
                CommonTraitUtils.add_trait(sim_info, trait_id_one)
            return True
        return False

    @staticmethod
    def add_trait_to_all_sims(trait_id: int, include_sim_callback: Callable[[SimInfo], bool]=None):
        """add_trait_to_all_sims(trait_id, include_sim_callback=None)

        Add a trait to all Sims that match the specified include filter.

        :param trait_id: The identifier of the Trait to add to all Sims.
        :type trait_id: int
        :param include_sim_callback: Only Sims that match this filter will have the Trait added.
        :type include_sim_callback: Callback[[SimInfo], bool], optional
        """
        for sim_info in CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback):
            if CommonTraitUtils.has_trait(sim_info, trait_id):
                continue
            CommonTraitUtils.add_trait(sim_info, trait_id)

    @staticmethod
    def remove_trait_from_all_sims(trait_id: int, include_sim_callback: Callable[[SimInfo], bool]=None):
        """remove_trait_from_all_sims(trait_id, include_sim_callback=None)

        Remove a trait from all Sims that match the specified include filter.

        :param trait_id: The identifier of the Trait to remove from all Sims.
        :type trait_id: int
        :param include_sim_callback: Only Sims that match this filter will have the Trait removed.
        :type include_sim_callback: Callback[[SimInfo], bool], optional
        """
        for sim_info in CommonSimUtils.get_instanced_sim_info_for_all_sims_generator(include_sim_callback=include_sim_callback):
            if not CommonTraitUtils.has_trait(sim_info, trait_id):
                continue
            CommonTraitUtils.remove_trait(sim_info, trait_id)

    @staticmethod
    def get_trait_id(trait_identifier: Union[int, Trait]) -> Union[int, None]:
        """get_trait_id(trait_identifier)

        Retrieve the decimal identifier of a Trait.

        :param trait_identifier: The identifier or instance of a Trait.
        :type trait_identifier: Union[int, Trait]
        :return: The decimal identifier of the Trait or None if the Trait does not have an id.
        :rtype: Union[int, None]
        """
        if isinstance(trait_identifier, int):
            return trait_identifier
        return getattr(trait_identifier, 'guid64', None)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(), fallback_return=None)
    def _load_trait_instance(trait_id: int) -> Union[Trait, None]:
        from sims4.resources import Types
        from sims4communitylib.utils.common_resource_utils import CommonResourceUtils
        return CommonResourceUtils.load_instance(Types.TRAIT, trait_id)
Пример #7
0
def _common_testing_show_choose_object_dialog(_connection: int = None):
    output = sims4.commands.CheatOutput(_connection)
    output('Showing test choose object dialog.')

    def _on_chosen(choice: str, outcome: CommonChoiceOutcome):
        output('Chose {} with result: {}.'.format(pformat(choice),
                                                  pformat(outcome)))

    try:
        # LocalizedStrings within other LocalizedStrings
        title_tokens = (CommonLocalizationUtils.create_localized_string(
            CommonStringId.TESTING_SOME_TEXT_FOR_TESTING,
            text_color=CommonLocalizedStringColor.GREEN), )
        description_tokens = (CommonLocalizationUtils.create_localized_string(
            CommonStringId.TESTING_TEST_TEXT_WITH_SIM_FIRST_AND_LAST_NAME,
            tokens=(CommonSimUtils.get_active_sim_info(), ),
            text_color=CommonLocalizedStringColor.BLUE), )
        from sims4communitylib.utils.common_icon_utils import CommonIconUtils
        options = [
            ObjectPickerRow(
                option_id=1,
                name=CommonLocalizationUtils.create_localized_string(
                    CommonStringId.TESTING_SOME_TEXT_FOR_TESTING),
                row_description=CommonLocalizationUtils.
                create_localized_string(
                    CommonStringId.TESTING_TEST_BUTTON_ONE),
                row_tooltip=None,
                icon=CommonIconUtils.load_checked_square_icon(),
                tag='Value 1'),
            ObjectPickerRow(
                option_id=2,
                name=CommonLocalizationUtils.create_localized_string(
                    CommonStringId.TESTING_SOME_TEXT_FOR_TESTING),
                row_description=CommonLocalizationUtils.
                create_localized_string(
                    CommonStringId.TESTING_TEST_BUTTON_TWO),
                row_tooltip=None,
                icon=CommonIconUtils.load_arrow_navigate_into_icon(),
                tag='Value 2'),
            ObjectPickerRow(
                option_id=3,
                name=CommonLocalizationUtils.create_localized_string(
                    'Value 3'),
                row_description=CommonLocalizationUtils.
                create_localized_string(
                    CommonStringId.TESTING_TEST_BUTTON_TWO),
                row_tooltip=None,
                icon=CommonIconUtils.load_arrow_navigate_into_icon(),
                tag='Value 3')
        ]
        dialog = CommonChooseObjectDialog(
            CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
            CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
            tuple(options),
            title_tokens=title_tokens,
            description_tokens=description_tokens,
            per_page=2)
        dialog.show(on_chosen=_on_chosen)
    except Exception as ex:
        CommonExceptionHandler.log_exception(ModInfo.get_identity().name,
                                             'Failed to show dialog',
                                             exception=ex)
        output('Failed to show dialog, please locate your exception log file.')
    output('Done showing.')
class CommonOutfitUtils:
    """Utilities for handling Sim outfits.

    """
    @staticmethod
    def is_every_day_category(outfit_category: OutfitCategory) -> bool:
        """is_every_day_category(outfit_category)

        Determine if an OutfitCategory is EVERYDAY

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.EVERYDAY. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.EVERYDAY

    @staticmethod
    def is_formal_category(outfit_category: OutfitCategory) -> bool:
        """is_formal_category(outfit_category)

        Determine if an OutfitCategory is FORMAL

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.FORMAL. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.FORMAL

    @staticmethod
    def is_athletic_category(outfit_category: OutfitCategory) -> bool:
        """is_athletic_category(outfit_category)

        Determine if an OutfitCategory is ATHLETIC

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.ATHLETIC. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.ATHLETIC

    @staticmethod
    def is_sleep_category(outfit_category: OutfitCategory) -> bool:
        """is_sleep_category(outfit_category)

        Determine if an OutfitCategory is SLEEP

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.SLEEP. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.SLEEP

    @staticmethod
    def is_party_category(outfit_category: OutfitCategory) -> bool:
        """is_party_category(outfit_category)

        Determine if an OutfitCategory is PARTY

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.PARTY. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.PARTY

    @staticmethod
    def is_bathing_category(outfit_category: OutfitCategory) -> bool:
        """is_bathing_category(outfit_category)

        Determine if an OutfitCategory is BATHING

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.BATHING. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.BATHING

    @staticmethod
    def is_career_category(outfit_category: OutfitCategory) -> bool:
        """is_career_category(outfit_category)

        Determine if an OutfitCategory is CAREER

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.CAREER. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.CAREER

    @staticmethod
    def is_situation_category(outfit_category: OutfitCategory) -> bool:
        """is_situation_category(outfit_category)

        Determine if an OutfitCategory is SITUATION

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.SITUATION. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.SITUATION

    @staticmethod
    def is_special_category(outfit_category: OutfitCategory) -> bool:
        """is_special_category(outfit_category)

        Determine if an OutfitCategory is SPECIAL

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.SPECIAL. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.SPECIAL

    @staticmethod
    def is_swimwear_category(outfit_category: OutfitCategory) -> bool:
        """is_swimwear_category(outfit_category)

        Determine if an OutfitCategory is SWIMWEAR

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.SWIMWEAR. False, if it is not.
        :rtype: bool
        """
        return outfit_category == OutfitCategory.SWIMWEAR

    @staticmethod
    def is_hot_weather_category(outfit_category: OutfitCategory) -> bool:
        """is_hot_weather_category(outfit_category)

        Determine if an OutfitCategory is HOTWEATHER

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.HOTWEATHER. False, if it is not.
        :rtype: bool
        """
        # noinspection PyBroadException
        try:
            return outfit_category == OutfitCategory.HOTWEATHER
        except:
            return False

    @staticmethod
    def is_cold_weather_category(outfit_category: OutfitCategory) -> bool:
        """is_cold_weather_category(outfit_category)

        Determine if an OutfitCategory is COLDWEATHER

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.COLDWEATHER. False, if it is not.
        :rtype: bool
        """
        # noinspection PyBroadException
        try:
            return outfit_category == OutfitCategory.COLDWEATHER
        except:
            return False

    @staticmethod
    def is_batuu_category(outfit_category: OutfitCategory) -> bool:
        """is_batuu_category(outfit_category)

        Determine if an OutfitCategory is BATUU

        :param outfit_category: The OutfitCategory to check.
        :type outfit_category: OutfitCategory
        :return: True, if the OutfitCategory is OutfitCategory.BATUU. False, if it is not.
        :rtype: bool
        """
        # noinspection PyBroadException
        try:
            return outfit_category == OutfitCategory.BATUU
        except:
            return False

    @staticmethod
    def get_all_outfit_categories() -> Tuple[OutfitCategory]:
        """get_all_outfit_categories()

        Retrieve a collection of all OutfitCategory types.

        :return: A collection of all OutfitCategories.
        :rtype: Tuple[OutfitCategory]
        """
        return tuple(OutfitCategory.values)

    @staticmethod
    def is_wearing_everyday_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_everyday_outfit(sim_info)

        Determine if a Sim is wearing an Everyday outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing an everyday outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_every_day_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_formal_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_formal_outfit(sim_info)

        Determine if a Sim is wearing a Formal outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a formal outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_formal_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_athletic_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_athletic_outfit(sim_info)

        Determine if a Sim is wearing an Athletic outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing an athletic outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_athletic_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_sleep_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_sleep_outfit(sim_info)

        Determine if a Sim is wearing a Sleep outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a sleep outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_sleep_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_party_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_party_outfit(sim_info)

        Determine if a Sim is wearing a Party outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a party outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_party_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_bathing_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_bathing_outfit(sim_info)

        Determine if a Sim is wearing a Bathing outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing their bathing/nude outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_bathing_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_career_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_career_outfit(sim_info)

        Determine if a Sim is wearing a Career outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a career outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_career_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_situation_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_situation_outfit(sim_info)

        Determine if a Sim is wearing a Situation outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a situation outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_situation_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_special_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_special_outfit(sim_info)

        Determine if a Sim is wearing a Special outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a special outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_special_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_swimwear_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_swimwear_outfit(sim_info)

        Determine if a Sim is wearing a Swimwear outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a swimwear outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_swimwear_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_hot_weather_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_hot_weather_outfit(sim_info)

        Determine if a Sim is wearing a Hot Weather outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a hot weather outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_hot_weather_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_cold_weather_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_cold_weather_outfit(sim_info)

        Determine if a Sim is wearing a Cold Weather outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a cold weather outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_cold_weather_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_batuu_outfit(sim_info: SimInfo) -> bool:
        """is_wearing_batuu_outfit(sim_info)

        Determine if a Sim is wearing a Batuu outfit.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a batuu outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.is_batuu_category(CommonOutfitUtils.get_current_outfit_category(sim_info))

    @staticmethod
    def is_wearing_towel(sim_info: SimInfo) -> bool:
        """is_wearing_towel(sim_info)

        Determine if a Sim is currently wearing a towel.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the sim is wearing a towel. False, if not.
        :rtype: bool
        """
        return CommonBuffUtils.has_buff(sim_info, CommonBuffId.IS_WEARING_TOWEL)

    @staticmethod
    def get_outfit_category_by_name(name: str) -> OutfitCategory:
        """get_outfit_category_by_name(name)

        Retrieve an OutfitCategory by its a name.

        :param name: The name of an outfit category.
        :type name: str
        :return: The OutfitCategory with the specified name or OutfitCategory.CURRENT_OUTFIT if no outfit category was found using the specified name.
        :rtype: OutfitCategory
        """
        upper_case_name = str(name).upper().strip()
        return CommonResourceUtils.get_enum_by_name(upper_case_name, OutfitCategory, default_value=OutfitCategory.CURRENT_OUTFIT)

    @staticmethod
    def get_current_outfit_category(sim_info: SimInfo) -> OutfitCategory:
        """get_current_outfit_category(sim_info)

        Retrieve the current OutfitCategory and Index of a Sim.

        :param sim_info: The Sim to get the outfit category of.
        :type sim_info: SimInfo
        :return: The OutfitCategory of the current outfit a Sim is wearing.
        :rtype: OutfitCategory
        """
        return CommonOutfitUtils.get_current_outfit(sim_info)[0]

    @staticmethod
    def get_current_outfit_index(sim_info: SimInfo) -> int:
        """get_current_outfit_index(sim_info)

        Retrieve the current OutfitCategory and Index of a Sim.

        .. note:: If a Sim has two Athletic outfits and they are wearing the second outfit, the index would be `1`.

        :param sim_info: The Sim to get the outfit index of.
        :type sim_info: SimInfo
        :return: The index of their current outfit relative to the outfits a Sim has in the current OutfitCategory.
        :rtype: int
        """
        return CommonOutfitUtils.get_current_outfit(sim_info)[1]

    @staticmethod
    def get_current_outfit(sim_info: SimInfo) -> Tuple[OutfitCategory, int]:
        """get_current_outfit(sim_info)

        Retrieve the current OutfitCategory and Index of the current sim.

        .. note:: If a Sim has two Athletic outfits and they are wearing the second outfit, the index would be `1`.

        :param sim_info: The Sim to get the current outfit of.
        :type sim_info: SimInfo
        :return: The OutfitCategory and index of the current outfit a Sim is wearing.
        :rtype: Tuple[OutfitCategory, int]
        """
        return sim_info.get_current_outfit()

    @staticmethod
    def get_outfit_data(sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None]=None) -> OutfitData:
        """get_outfit_data(sim_info, outfit_category_and_index=None)

        Retrieve OutfitData for the specified OutfitCategory and Index of a Sim.

        :param sim_info: The Sim to retrieve outfit data of.
        :type sim_info: SimInfo
        :param outfit_category_and_index: The OutfitCategory and Index of the outfit to retrieve data from. Default is the current outfit.
        :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional
        :return: Outfit Data for the specified outfit.
        :rtype: OutfitData
        """
        if outfit_category_and_index is None:
            outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info)
        return sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1])

    @staticmethod
    def has_cas_part_attached(sim_info: SimInfo, cas_part_id: int, outfit_category_and_index: Tuple[OutfitCategory, int]=None) -> bool:
        """has_any_cas_parts_attached(sim_info, cas_part_id, outfit_category_and_index=None)

        Determine if any of the specified CAS Parts are attached to the Sim.

        :param sim_info: An instance of a Sim.
        :type sim_info: SimInfo
        :param cas_part_id: A CAS Part identifier.
        :type cas_part_id: int
        :param outfit_category_and_index: The OutfitCategory and Index of the outfit to check. Default is the current outfit.
        :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional
        :return: True, if the Sim has the specified CAS Parts attached to the specified outfit. False, if not.
        :rtype: bool
        """
        return CommonOutfitUtils.has_any_cas_parts_attached(sim_info, (cas_part_id, ), outfit_category_and_index=outfit_category_and_index)

    @staticmethod
    def has_any_cas_parts_attached(sim_info: SimInfo, cas_part_ids: Tuple[int], outfit_category_and_index: Tuple[OutfitCategory, int]=None) -> bool:
        """has_any_cas_parts_attached(sim_info, cas_part_ids, outfit_category_and_index=None)

        Determine if any of the specified CAS Parts are attached to the Sim.

        :param sim_info: An instance of a Sim.
        :type sim_info: SimInfo
        :param cas_part_ids: A collection of CAS Part identifiers.
        :type cas_part_ids: Tuple[int]
        :param outfit_category_and_index: The OutfitCategory and Index of the outfit to check. Default is the current outfit.
        :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional
        :return: True, if the Sim has any of the specified CAS Parts attached to the specified outfit. False, if not.
        :rtype: bool
        """
        body_parts = CommonOutfitUtils.get_outfit_parts(sim_info, outfit_category_and_index=outfit_category_and_index)
        if not body_parts:
            return False
        outfit_part_ids = body_parts.values()
        for cas_part_id in cas_part_ids:
            if cas_part_id in outfit_part_ids:
                return True
        return False

    @staticmethod
    def get_outfit_parts(sim_info: SimInfo, outfit_category_and_index: Union[Tuple[OutfitCategory, int], None]=None) -> Dict[BodyType, int]:
        """get_outfit_parts(sim_info, outfit_category_and_index=None)

        Retrieve Outfit Parts for the specified OutfitCategory and Index of a Sim.

        :param sim_info: The Sim to retrieve outfit parts of.
        :type sim_info: SimInfo
        :param outfit_category_and_index: The OutfitCategory and Index of the outfit to retrieve data from. Default is the current outfit.
        :type outfit_category_and_index: Union[Tuple[OutfitCategory, int], None], optional
        :return: A dictionary of body types and cas parts in those body types for the outfit of a Sim.
        :rtype: Dict[BodyType, int]
        """
        if outfit_category_and_index is None:
            outfit_category_and_index = CommonOutfitUtils.get_current_outfit(sim_info)
        outfit_data = sim_info.get_outfit(outfit_category_and_index[0], outfit_category_and_index[1])
        if outfit_data is None:
            return dict()
        return dict(zip(list(outfit_data.body_types), list(outfit_data.part_ids)))

    @staticmethod
    def set_current_outfit(sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]):
        """set_current_outfit(sim_info, outfit_category_and_index)

        Set the current outfit of a Sim to the specified OutfitCategory and Index.

        :param sim_info: The Sim to change the outfit of.
        :type sim_info: SimInfo
        :param outfit_category_and_index: The OutfitCategory and index to change to.
        :type outfit_category_and_index: Tuple[OutfitCategory, int]
        """
        sim_info.set_current_outfit(outfit_category_and_index)

    @staticmethod
    def set_outfit_dirty(sim_info: SimInfo, outfit_category: OutfitCategory):
        """set_outfit_dirty(sim_info, outfit_category)

        Flag the specified OutfitCategory of a Sim as dirty.
        This will tell the game that it needs to be updated.

        :param sim_info: The Sim to flag the OutfitCategory for.
        :type sim_info: SimInfo
        :param outfit_category: The OutfitCategory being flagged.
        :type outfit_category: OutfitCategory
        """
        sim_info.set_outfit_dirty(outfit_category)

    @staticmethod
    def set_outfit_clean(sim_info: SimInfo, outfit_category: OutfitCategory):
        """set_outfit_clean(sim_info, outfit_category)

        Flag the specified OutfitCategory of a Sim as clean.

        :param sim_info: The Sim to flag the OutfitCategory for.
        :type sim_info: SimInfo
        :param outfit_category: The OutfitCategory being flagged.
        :type outfit_category: OutfitCategory
        """
        sim_info.clear_outfit_dirty(outfit_category)

    @staticmethod
    def generate_outfit(sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]) -> bool:
        """generate_outfit(sim_info, outfit_category_and_index)

        Generate an outfit for a Sim for the specified OutfitCategory and Index.

        .. note:: If an outfit exists in the specified OutfitCategory and Index, already, it will be overridden.

        :param sim_info: The Sim to generate an outfit for.
        :type sim_info: SimInfo
        :param outfit_category_and_index: The OutfitCategory and Index of the outfit to generate.
        :type outfit_category_and_index: Tuple[OutfitCategory, int]
        :return: True, if an outfit was generated successfully. False, if not.
        :rtype: bool
        """
        try:
            sim_info.on_outfit_generated(sim_info, CommonOutfitUtils.get_current_outfit(sim_info))
            sim_info.generate_outfit(*outfit_category_and_index)
            return True
        except Exception as ex:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Problem occurred running function \'{}\'.'.format(CommonOutfitUtils.generate_outfit.__name__), exception=ex)
        return False

    @staticmethod
    def resend_outfits(sim_info: SimInfo) -> bool:
        """resend_outfits(sim_info)

        Resend outfit data to a Sim to refresh their outfits.

        :param sim_info: The Sim to resend the outfit for.
        :type sim_info: SimInfo
        :return: True, if outfits were resent successfully. False, if not.
        :rtype: bool
        """
        try:
            sim_info.resend_outfits()
            return True
        except Exception as ex:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Problem occurred running function \'{}\'.'.format(CommonOutfitUtils.resend_outfits.__name__), exception=ex)
        return False

    @staticmethod
    def get_previous_outfit(sim_info: SimInfo, default_outfit_category_and_index: Tuple[OutfitCategory, int]=(OutfitCategory.EVERYDAY, 0)) -> Tuple[OutfitCategory, int]:
        """get_previous_outfit(sim_info, default_outfit_category_and_index=(OutfitCategory.EVERYDAY, 0))

        Retrieve the previous outfit a Sim was wearing before their current outfit.

        :param sim_info: The Sim to get the previous outfit of.
        :type sim_info: SimInfo
        :param default_outfit_category_and_index: A default OutfitCategory and index if no previous outfit was found.
        :type default_outfit_category_and_index: Tuple[OutfitCategory, int], optional
        :return: The OutfitCategory and Index of the outfit a Sim was wearing before their current outfit or the default if none was found.
        :rtype: Tuple[OutfitCategory, int]
        """
        return sim_info.get_previous_outfit() or default_outfit_category_and_index

    @staticmethod
    def remove_previous_outfit(sim_info: SimInfo):
        """remove_previous_outfit(sim_info)

        Remove the outfit a Sim was wearing before their current outfit, from the cache.

        :param sim_info: The Sim to remove the outfit from.
        :type sim_info: SimInfo
        """
        sim_info.set_previous_outfit(None, force=True)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(), fallback_return=False)
    def has_outfit(sim_info: SimInfo, outfit_category_and_index: Tuple[OutfitCategory, int]) -> bool:
        """has_outfit(sim_info, outfit_category_and_index)

        Determine if a Sim has an existing outfit in the specified OutfitCategory and Index.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param outfit_category_and_index: The OutfitCategory and index to locate.
        :type outfit_category_and_index: Tuple[OutfitCategory, int], optional
        :return: True, if the Sim has the specified OutfitCategory and Index. False, if not.
        :rtype: bool
        """
        return sim_info.has_outfit(outfit_category_and_index)

    @staticmethod
    def update_outfits(sim_info: SimInfo) -> bool:
        """update_outfits(sim_info)

        Update all outfits of a Sim.

        :param sim_info: The Sim to update outfits for.
        :type sim_info: SimInfo
        :return: True, if the outfits were updated successfully. False, if not.
        :rtype: bool
        """
        try:
            sim_info.on_outfit_changed(sim_info, CommonOutfitUtils.get_current_outfit(sim_info))
            CommonOutfitUtils.resend_outfits(sim_info)
            sim_info.appearance_tracker.evaluate_appearance_modifiers()
            return True
        except Exception as ex:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Problem occurred running function \'{}\'.'.format(CommonOutfitUtils.update_outfits.__name__), exception=ex)
        return False
Пример #9
0
"""
This file is part of the Sims 4 Community Library, licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International public license (CC BY-NC-ND 4.0).
https://creativecommons.org/licenses/by-nc-nd/4.0/
https://creativecommons.org/licenses/by-nc-nd/4.0/legalcode

Copyright (c) COLONOLNUTTY
"""
from sims.sim_info import SimInfo
from sims4communitylib.modinfo import ModInfo
from sims4communitylib.utils.common_log_registry import CommonLogRegistry
from sims4communitylib.utils.sims.common_age_utils import CommonAgeUtils
from sims4communitylib.utils.sims.common_species_utils import CommonSpeciesUtils

log = CommonLogRegistry.get().register_log(ModInfo.get_identity().name, 's4cl_age_species_utils')


class CommonAgeSpeciesUtils:
    """ Utilities for combinations of a Sims age and species. """
    @staticmethod
    def is_baby_human(sim_info: SimInfo) -> bool:
        """
            Determine if a sim is a Baby Human.
        """
        return CommonAgeUtils.is_baby(sim_info) and CommonSpeciesUtils.is_human(sim_info)

    @staticmethod
    def is_toddler_human(sim_info: SimInfo) -> bool:
        """
            Determine if a sim is a Toddler Human.
        """
        return CommonAgeUtils.is_toddler(sim_info) and CommonSpeciesUtils.is_human(sim_info)
class CommonBasicNotification:
    """
        Use to create a basic notification.
    """
    def __init__(self,
                 title_identifier: Union[int, LocalizedString],
                 description_identifier: Union[int, LocalizedString],
                 title_tokens: Tuple[Any] = (),
                 description_tokens: Tuple[Any] = (),
                 urgency: UiDialogNotification.
                 UiDialogNotificationUrgency = UiDialogNotification.
                 UiDialogNotificationUrgency.DEFAULT,
                 information_level: UiDialogNotification.
                 UiDialogNotificationLevel = UiDialogNotification.
                 UiDialogNotificationLevel.SIM,
                 expand_behavior: UiDialogNotification.
                 UiDialogNotificationExpandBehavior = UiDialogNotification.
                 UiDialogNotificationExpandBehavior.USER_SETTING):
        """
            Create a notification
        :param title_identifier: A decimal identifier of the title text.
        :param description_identifier: A decimal identifier of the description text.
        :param title_tokens: Tokens to format into the title.
        :param description_tokens: Tokens to format into the description.
        :param urgency: The urgency to which the notification will appear. (URGENT makes it orange)
        :param information_level: The information level of the notification.
        :param expand_behavior: Specify how the notification will expand.
        """
        self.title = CommonLocalizationUtils.create_localized_string(
            title_identifier, tokens=title_tokens)
        self.description = CommonLocalizationUtils.create_localized_string(
            description_identifier, tokens=description_tokens)
        self.visual_type = UiDialogNotification.UiDialogNotificationVisualType.INFORMATION
        self.urgency = urgency
        self.information_level = information_level
        self.expand_behavior = expand_behavior
        self.ui_responses = ()

    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name)
    def show(self,
             icon: IconInfoData = None,
             secondary_icon: IconInfoData = None):
        """
            Show the notification to the player.
        """
        _notification = self._create_dialog()
        if _notification is None:
            return

        _notification.show_dialog(icon_override=icon,
                                  secondary_icon_override=secondary_icon)

    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name,
                                             fallback_return=None)
    def _create_dialog(self) -> Union[UiDialogNotification, None]:
        return UiDialogNotification.TunableFactory().default(
            None,
            title=lambda *args, **kwargs: self.title,
            text=lambda *args, **kwargs: self.description,
            visual_type=self.visual_type,
            urgency=self.urgency,
            information_level=self.information_level,
            ui_responses=self.ui_responses,
            expand_behavior=self.expand_behavior)
Пример #11
0
class CommonBuffUtils:
    """Utilities for manipulating Buffs on Sims.

    """
    @staticmethod
    def has_fertility_boosting_buff(sim_info: SimInfo) -> bool:
        """has_fertility_boosting_buff(sim_info)

        Determine if any fertility boosting buffs are currently active on a sim.

        .. note::

            Fertility Boosting Buffs:

            - Fertility Potion
            - Fertility Potion Masterwork
            - Fertility Potion Normal
            - Fertility Potion Outstanding
            - Massage Table Fertility Boost
            - Massage Table Fertility Boost Incense

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if they have any fertility boosting buffs. False, if not.
        :rtype: bool
        """
        buff_ids = (
            CommonBuffId.OBJECT_HERBALIST_POTION_FERTILITY_POTION,
            CommonBuffId.OBJECT_HERBALIST_POTION_FERTILITY_POTION_MASTERWORK,
            CommonBuffId.OBJECT_HERBALIST_POTION_FERTILITY_POTION_NORMAL,
            CommonBuffId.OBJECT_HERBALIST_POTION_FERTILITY_POTION_OUTSTANDING,
            CommonBuffId.OBJECT_MASSAGE_TABLE_FERTILITY_BOOST,
            CommonBuffId.OBJECT_MASSAGE_TABLE_FERTILITY_BOOST_INCENSE
        )
        return CommonBuffUtils.has_buff(sim_info, *buff_ids)

    @staticmethod
    def has_morning_person_buff(sim_info: SimInfo) -> bool:
        """has_morning_person_buff(sim_info)

        Determine if any Morning Person Trait buffs are currently active on a Sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if they have any morning person buffs. False, if not.
        :rtype: bool
        """
        buff_ids = (
            CommonBuffId.TRAIT_MORNING_PERSON,
            CommonBuffId.TRAIT_MORNING_PERSON_ACTIVE,
            CommonBuffId.TRAIT_MORNING_PERSON_CHECK_ACTIVE
        )
        return CommonBuffUtils.has_buff(sim_info, *buff_ids)

    @staticmethod
    def has_night_owl_buff(sim_info: SimInfo) -> bool:
        """has_night_owl_buff(sim_info)

        Determine if any Night Owl Trait buffs are currently active on a sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if they have any night owl buffs. False, if not.
        :rtype: bool
        """
        buff_ids = (
            CommonBuffId.TRAIT_NIGHT_OWL,
            CommonBuffId.TRAIT_NIGHT_OWL_ACTIVE,
            CommonBuffId.TRAIT_NIGHT_OWL_CHECK_ACTIVE
        )
        return CommonBuffUtils.has_buff(sim_info, *buff_ids)

    @staticmethod
    def has_buff(sim_info: SimInfo, *buff_ids: int) -> bool:
        """has_buff(sim_info, *buff_ids)

        Determine if any of the specified buffs are currently active on a sim.

        :param sim_info: The sim being checked.
        :type sim_info: SimInfo
        :param buff_ids: The decimal identifiers of Buffs.
        :type buff_ids: int
        :return: True if the sim has any of the specified buffs.
        :rtype: int
        """
        if sim_info is None:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Argument \'sim_info\' was \'None\' for \'{}\' of class \'{}\''.format(CommonBuffUtils.has_buff.__name__, CommonBuffUtils.__name__))
            return False
        if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF):
            return False
        if not buff_ids:
            return False
        sim_buffs = CommonBuffUtils.get_buffs(sim_info)
        for buff in sim_buffs:
            buff_id = CommonBuffUtils.get_buff_id(buff)
            if buff_id in buff_ids:
                return True
        return False

    @staticmethod
    def get_buffs(sim_info: SimInfo) -> List[Buff]:
        """get_buffs(sim_info)

        Retrieve all buffs currently active on a Sim.

        :param sim_info: The Sim to retrieve the buffs of.
        :type sim_info: SimInfo
        :return: A collection of currently active buffs on the Sim.
        :rtype: Tuple[Buff]
        """
        if sim_info is None:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Argument \'sim_info\' was \'None\' for \'{}\' of class \'{}\''.format(CommonBuffUtils.get_buffs.__name__, CommonBuffUtils.__name__))
            return list()
        if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF):
            return list()
        from objects.components.buff_component import BuffComponent
        buff_component: BuffComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.BUFF)
        buffs = list()
        for buff in buff_component:
            if buff is None or not isinstance(buff, Buff):
                continue
            buffs.append(buff)
        return buffs

    @staticmethod
    def add_buff(sim_info: SimInfo, *buff_ids: int, buff_reason: Union[int, str, LocalizedString]=None) -> bool:
        """add_buff(sim_info, *buff_ids, buff_reason=None)

        Add the specified buffs to a sim.

        :param sim_info: The sim to add the specified buffs to.
        :type sim_info: SimInfo
        :param buff_ids: The decimal identifiers of buffs to add.
        :type buff_ids: int
        :param buff_reason: The text that will display when the player hovers over the buffs. What caused the buffs to be added.
        :type buff_reason: Union[int, str, LocalizedString], optional
        :return: True, if all of the specified buffs were successfully added. False, if not.
        :rtype: bool
        """
        if sim_info is None:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Argument \'sim_info\' was \'None\' for \'{}\' of class \'{}\''.format(CommonBuffUtils.add_buff.__name__, CommonBuffUtils.__name__))
            return False
        if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF):
            return False
        localized_buff_reason = CommonLocalizationUtils.create_localized_string(buff_reason)
        success = True
        for buff_identifier in buff_ids:
            buff_instance = CommonBuffUtils._load_buff_instance(buff_identifier)
            if buff_instance is None:
                continue
            if not sim_info.add_buff_from_op(buff_instance, buff_reason=localized_buff_reason):
                success = False
        return success

    @staticmethod
    def remove_buff(sim_info: SimInfo, *buff_ids: int) -> bool:
        """remove_buff(sim_info, *buff_ids)

        Remove the specified buffs from a sim.

        :param sim_info: The sim to remove the specified buffs from.
        :type sim_info: SimInfo
        :param buff_ids: The decimal identifiers of Buffs to remove.
        :type buff_ids: int
        :return: True, if all of the specified buffs were successfully removed. False, if not.
        :rtype: bool
        """
        if sim_info is None:
            CommonExceptionHandler.log_exception(ModInfo.get_identity(), 'Argument \'sim_info\' was \'None\' for \'{}\' of class \'{}\''.format(CommonBuffUtils.remove_buff.__name__, CommonBuffUtils.__name__))
            return False
        if not CommonComponentUtils.has_component(sim_info, CommonComponentType.BUFF):
            return False
        success = True
        for buff_identifier in buff_ids:
            buff_instance = CommonBuffUtils._load_buff_instance(buff_identifier)
            if buff_instance is None:
                continue
            if not sim_info.remove_buff_by_type(buff_instance):
                success = False
        return success

    @staticmethod
    def get_buff_id(buff_identifier: Union[int, Buff]) -> Union[int, None]:
        """get_buff_id(buff_identifier)

        Retrieve the decimal identifier of a Buff.

        :param buff_identifier: The identifier or instance of a Buff.
        :type buff_identifier: Union[int, Buff]
        :return: The decimal identifier of the Buff or None if the Buff does not have an id.
        :rtype: Union[int, None]
        """
        if isinstance(buff_identifier, int):
            return buff_identifier
        return getattr(buff_identifier, 'guid64', None)

    @staticmethod
    def get_buff_name(buff: Buff) -> Union[str, None]:
        """get_buff_name(buff)

        Retrieve the Name of a Buff.

        :param buff: An instance of a Buff.
        :type buff: Buff
        :return: The name of a Buff or None if a problem occurs.
        :rtype: Union[str, None]
        """
        if buff is None:
            return None
        # noinspection PyBroadException
        try:
            return buff.__class__.__name__ or ''
        except:
            return ''

    @staticmethod
    def get_buff_names(buffs: Iterator[Buff]) -> Tuple[str]:
        """get_buff_names(buffs)

        Retrieve the Names of a collection of Buffs.

        :param buffs: A collection of Buff instances.
        :type buffs: Iterator[Buff]
        :return: A collection of names for all specified Buffs.
        :rtype: Tuple[str]
        """
        if buffs is None or not buffs:
            return tuple()
        names: List[str] = []
        for buff in buffs:
            # noinspection PyBroadException
            try:
                name = CommonBuffUtils.get_buff_name(buff)
                if not name:
                    continue
            except:
                continue
            names.append(name)
        return tuple(names)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(), fallback_return=None)
    def _load_buff_instance(buff_identifier: int) -> Union[Buff, None]:
        from sims4.resources import Types
        from sims4communitylib.utils.common_resource_utils import CommonResourceUtils
        return CommonResourceUtils.load_instance(Types.BUFF, buff_identifier)
Пример #12
0
class CommonSimStatisticUtils:
    """Utilities for manipulating the Statistics of Sims.

    """
    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def has_statistic(sim_info: SimInfo, statistic_id: int) -> bool:
        """Determine if a sim has any of the specified Statistics.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to check.
        :type statistic_id: int
        :return: True, if the Sim has any of the statistics. False, if not.
        :rtype: bool
        """
        return CommonSimStatisticUtils.has_statistics(sim_info, (statistic_id,))

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def has_statistics(sim_info: SimInfo, statistic_ids: Iterator[int]) -> bool:
        """has_statistics(sim_info, statistic_ids)

        Determine if a sim has any of the specified Statistics.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_ids: An iterator of identifiers for statistics to check.
        :type statistic_ids: int
        :return: True, if the Sim has any of the statistics. False, if not.
        :rtype: bool
        """
        for statistic_id in statistic_ids:
            response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id)
            if response.statistics_tracker is None or response.statistic_instance is None:
                continue
            if response.statistics_tracker.has_statistic(response.statistic_instance):
                return True
        return False

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def is_statistic_locked(sim_info: SimInfo, statistic_id: int, add_dynamic: bool=True, add: bool= False) -> bool:
        """is_statistic_locked(sim_info, statistic_id, add_dynamic=True, add=False)

        Determine if a statistic is locked for the specified Sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to check.
        :type statistic_id: int
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if the statistic is locked. False, if not.
        :rtype: bool
        """
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id, add_dynamic=add_dynamic)
        if response.statistic_instance is None:
            return False
        if response.statistics_tracker is None:
            return False
        statistic = response.statistics_tracker.get_statistic(response.statistic_instance, add=add)
        if statistic is None:
            return False
        return statistic.get_decay_rate_modifier() == 0 or response.statistics_component.is_locked(statistic)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=0.0)
    def get_statistic_level(sim_info: SimInfo, statistic_id: int) -> float:
        """get_statistic_level(sim_info, statistic_id)

        Retrieve the User Value of a Statistic for the specified Sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to retrieve the user value of.
        :type statistic_id: int
        :return: The value of the statistic, `-1.0` if the statistic is not found, or `0.0` if a problem occurs.
        :rtype: float
        """
        statistic = CommonSimStatisticUtils.get_statistic(sim_info, statistic_id)
        if statistic is None:
            return 0.0
        return statistic.get_user_value()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=None)
    def get_statistic(sim_info: SimInfo, statistic_id: int, add_dynamic: bool=True, add: bool=False) -> Union[BaseStatistic, None]:
        """get_statistic(sim_info, statistic_id, add_dynamic=True, add=False)

        Retrieve a Statistic for the specified Sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to retrieve of.
        :type statistic_id: int
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: An instance of the statistic or None if a problem occurs.
        :rtype: Union[BaseStatistic, None]
        """
        if sim_info is None:
            return None
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id, add_dynamic=add_dynamic)
        if response.statistics_tracker is None or response.statistic_instance is None:
            return None
        return response.statistics_tracker.get_statistic(response.statistic_instance, add=add)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=0.0)
    def get_statistic_value(sim_info: SimInfo, statistic_id: int, add_dynamic: bool=True, add: bool=False) -> float:
        """get_statistic_value(sim_info, statistic_id, add_dynamic=True, add=False)

        Retrieve the Value of a Statistic for the specified Sim.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to retrieve the value of.
        :type statistic_id: int
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: The value of the statistic, `-1.0` if the statistic is not found, or `0.0` if a problem occurs.
        :rtype: float
        """
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id, add_dynamic=add_dynamic)
        statistic_instance = response.statistic_instance
        if statistic_instance is None:
            return -1.0
        if response.statistics_tracker is not None:
            statistic = response.statistics_tracker.get_statistic(statistic_instance, add=add)
            if statistic is not None:
                return statistic.get_value()
        if hasattr(statistic_instance, 'get_initial_value'):
            return statistic_instance.get_initial_value()
        return statistic_instance.default_value

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def set_statistic_value(sim_info: SimInfo, statistic_id: int, value: float, add_dynamic: bool=True, add: bool=True) -> bool:
        """set_statistic_value(sim_info, statistic_id, value, add_dynamic=True, add=True)

        Set the Value of a Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to add a value to.
        :type statistic_id: int
        :param value: The amount to add.
        :type value: float
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id, add_dynamic=add_dynamic)
        if response.statistics_tracker is None or response.statistic_instance is None:
            return False
        response.statistics_tracker.set_value(response.statistic_instance, value, add=add)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def set_statistic_user_value(sim_info: SimInfo, statistic_id: int, value: float, add_dynamic: bool=True, add: bool=True) -> bool:
        """set_statistic_user_value(sim_info, statistic_id, value, add_dynamic=True, add=True)

        Set the User Value of a Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to add a user value to.
        :type statistic_id: int
        :param value: The amount to add.
        :type value: float
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        statistic = CommonSimStatisticUtils.get_statistic(sim_info, statistic_id, add_dynamic=add_dynamic, add=add)
        if statistic is None:
            return False
        return statistic.set_user_value(value)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def add_statistic_value(sim_info: SimInfo, statistic_id: int, value: float, add_dynamic: bool=True, add: bool=True) -> bool:
        """add_statistic_value(sim_info, statistic_id, value, add_dynamic=True, add=True)

        Change the Value of a Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to add a value to.
        :type statistic_id: int
        :param value: The amount to add.
        :type value: float
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id, add_dynamic=add_dynamic)
        if response.statistics_tracker is None or response.statistic_instance is None:
            return False
        response.statistics_tracker.add_value(response.statistic_instance, value, add=add)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def remove_statistic(sim_info: SimInfo, statistic_id: int) -> bool:
        """remove_statistic(sim_info, statistic_id)

        Remove a Statistic from the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to remove.
        :type statistic_id: int
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        response = CommonSimStatisticUtils._get_statistics_tracker(sim_info, statistic_id)
        if response.statistics_tracker is None or response.statistic_instance is None:
            return False
        response.statistics_tracker.remove_statistic(response.statistic_instance)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def add_statistic_modifier(sim_info: SimInfo, statistic_id: int, value: float, add_dynamic: bool=True, add: bool=True) -> bool:
        """add_statistic_modifier(sim_info, statistic_id, value, add_dynamic=True, add=True)

        Add a Modifier to the specified Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic containing the modifier.
        :type statistic_id: int
        :param value: The modifier to add.
        :type value: float
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        statistic = CommonSimStatisticUtils.get_statistic(sim_info, statistic_id, add_dynamic=add_dynamic, add=add)
        if statistic is None:
            return False
        statistic.add_statistic_modifier(value)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def remove_statistic_modifier(sim_info: SimInfo, statistic_id: int, value: float, add_dynamic: bool=True, add: bool=True) -> bool:
        """remove_statistic_modifier(sim_info, statistic_id, value, add_dynamic=True, add=True)

        Remove a Modifier from the specified Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to remove the modifier from.
        :type statistic_id: int
        :param value: The modifier to remove.
        :type value: float
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        statistic = CommonSimStatisticUtils.get_statistic(sim_info, statistic_id, add_dynamic=add_dynamic, add=add)
        if statistic is None:
            return False
        statistic.remove_statistic_modifier(value)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=False)
    def remove_all_statistic_modifiers_for_statistic(sim_info: SimInfo, statistic_id: int, add_dynamic: bool=True, add: bool=True) -> bool:
        """remove_all_statistic_modifiers_for_statistic(sim_info, statistic_id, add_dynamic=True, add=True)

        Remove all Modifiers from the specified Statistic for the specified Sim.

        :param sim_info: The Sim to modify.
        :type sim_info: SimInfo
        :param statistic_id: The identifier of the statistic to remove modifiers from.
        :type statistic_id: int
        :param add_dynamic: Add the statistic components to the Sim.
        :type add_dynamic: bool, optional
        :param add: Add the statistic to the Sim.
        :type add: bool, optional
        :return: True, if successful. False, if not successful.
        :rtype: bool
        """
        if sim_info is None:
            return False
        statistic = CommonSimStatisticUtils.get_statistic(sim_info, statistic_id, add_dynamic=add_dynamic, add=add)
        if statistic is None:
            return False
        if statistic._statistic_modifiers is None:
            return False
        for value in list(statistic._statistic_modifiers):
            statistic.remove_statistic_modifier(value)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity().name, fallback_return=None)
    def _get_statistics_tracker(sim_info: SimInfo, statistic_id: int, add_dynamic: bool=True) -> CommonGetStatisticTrackerResponse:
        if sim_info is None:
            return CommonGetStatisticTrackerResponse(None, None, None)
        statistic_instance = CommonStatisticUtils._load_statistic_instance(statistic_id)
        if statistic_instance is None:
            return CommonGetStatisticTrackerResponse(None, None, None)
        statistics_component: StatisticComponent = CommonComponentUtils.get_component(sim_info, CommonComponentType.STATISTIC, add_dynamic=add_dynamic)
        if statistics_component is None:
            return CommonGetStatisticTrackerResponse(None, statistic_instance, None)
        return CommonGetStatisticTrackerResponse(statistics_component.get_tracker(statistic_instance), statistic_instance, statistics_component)
class CommonInteractionUtils:
    """Utilities for manipulating Interactions.

    """
    @staticmethod
    def get_interaction_id(
            interaction_identifier: Union[int,
                                          Interaction]) -> Union[int, None]:
        """get_interaction_id(interaction_identifier)

        Retrieve the decimal identifier of an Interaction.

        :param interaction_identifier: The identifier or instance of a Interaction.
        :type interaction_identifier: Union[int, Interaction]
        :return: The decimal identifier of the Interaction or None if the Interaction does not have an id.
        :rtype: Union[int, None]
        """
        if isinstance(interaction_identifier, int):
            return interaction_identifier
        return getattr(interaction_identifier, 'guid64', None)

    @staticmethod
    def is_social_mixer_interaction(interaction: Interaction) -> bool:
        """is_social_mixer_interaction(interaction)

        Determine if an interaction is a Social Mixer interaction.

        :param interaction: An instance of an Interaction.
        :type interaction: Interaction
        :return: True, if the interaction is a Social Mixer interaction. False, if not.
        """
        if interaction is None:
            return False
        return interaction.is_social

    @staticmethod
    def is_super_interaction(interaction: Interaction) -> bool:
        """is_super_interaction(interaction)

        Determine if an interaction is a Super interaction.

        :param interaction: An instance of an Interaction.
        :type interaction: Interaction
        :return: True, if the interaction is a Super interaction. False, if not.
        """
        if interaction is None:
            return False
        return interaction.is_super

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def get_interaction_display_name(
        interaction: Interaction, tokens: Iterator[Any] = ()
    ) -> Union[LocalizedString, None]:
        """get_interaction_display_name(interaction, tokens=())

        Retrieve the display name of an interaction.

        :param interaction: An instance of an interaction.
        :type interaction: Interaction
        :param tokens: A collection of tokens to format into the display name.
        :type tokens: Iterator[Any]
        :return: An instance of type LocalizedString or None if a problem occurs.
        :rtype: Union[LocalizedString, None]
        """
        from sims4communitylib.utils.localization.common_localization_utils import CommonLocalizationUtils
        if interaction is None or interaction.display_name is None:
            return None
        return CommonLocalizationUtils.create_localized_string(
            interaction.display_name._string_id, tokens=tuple(tokens))

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def get_interaction_short_name(
            interaction: Interaction) -> Union[str, None]:
        """get_interaction_short_name(interaction)

        Retrieve the Short Name of an Interaction.

        :param interaction: An instance of an interaction.
        :type interaction: Interaction
        :return: The short name of an interaction or None if a problem occurs.
        :rtype: Union[str, None]
        """
        if interaction is None:
            return None
        # noinspection PyBroadException
        try:
            return str(interaction.shortname()
                       or '') or interaction.__class__.__name__
        except:
            return ''

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def get_interaction_short_names(
            interactions: Iterator[Interaction]) -> Tuple[str]:
        """get_interaction_short_names(interactions)

        Retrieve the Short Names of a collection of Interactions.

        :param interactions: A collection of interaction instances.
        :type interactions: Iterator[Interaction]
        :return: A collection of short names of all interaction instances.
        :rtype: Tuple[str]
        """
        if interactions is None or not interactions:
            return tuple()
        short_names: List[str] = []
        for interaction in interactions:
            # noinspection PyBroadException
            try:
                short_name = CommonInteractionUtils.get_interaction_short_name(
                    interaction)
                if not short_name:
                    continue
            except:
                continue
            short_names.append(short_name)
        return tuple(short_names)

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(
        ModInfo.get_identity(), )
    def _load_interaction_instance_manager(
    ) -> Union[InteractionInstanceManager, None]:
        return services.get_instance_manager(Types.INTERACTION)

    @staticmethod
    def _load_interaction_instance(
            interaction_identifier: int) -> Union[Interaction, None]:
        if interaction_identifier is None:
            return None
        return CommonResourceUtils.load_instance(Types.INTERACTION,
                                                 interaction_identifier)
 def get_mod_identity(cls) -> CommonModIdentity:
     # !!!Override with the CommonModIdentity of your own mod!!!
     from sims4communitylib.modinfo import ModInfo
     return ModInfo.get_identity()
Пример #15
0
def _common_testing_show_choose_object_option_dialog(_connection: int = None):
    output = sims4.commands.CheatOutput(_connection)
    output('Showing test choose object option dialog.')

    def _on_option_chosen(option_identifier: str, choice: str):
        output('Chose option {} with value: {}.'.format(
            pformat(option_identifier), pformat(choice)))

    try:
        # LocalizedStrings within other LocalizedStrings
        title_tokens = (CommonLocalizationUtils.create_localized_string(
            CommonStringId.TESTING_SOME_TEXT_FOR_TESTING,
            text_color=CommonLocalizedStringColor.GREEN), )
        description_tokens = (CommonLocalizationUtils.create_localized_string(
            CommonStringId.TESTING_TEST_TEXT_WITH_SIM_FIRST_AND_LAST_NAME,
            tokens=(CommonSimUtils.get_active_sim_info(), ),
            text_color=CommonLocalizedStringColor.BLUE), )
        option_dialog = CommonChooseObjectOptionDialog(
            CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
            CommonStringId.TESTING_TEST_TEXT_WITH_STRING_TOKEN,
            title_tokens=title_tokens,
            description_tokens=description_tokens,
            per_page=2)

        from sims4communitylib.utils.common_icon_utils import CommonIconUtils

        option_dialog.add_option(
            CommonDialogObjectOption(
                'Option 1',
                'Value 1',
                CommonDialogOptionContext(
                    CommonStringId.TESTING_SOME_TEXT_FOR_TESTING,
                    CommonStringId.TESTING_TEST_BUTTON_ONE,
                    icon=CommonIconUtils.load_checked_square_icon()),
                on_chosen=_on_option_chosen))

        option_dialog.add_option(
            CommonDialogObjectOption(
                'Option 2',
                'Value 2',
                CommonDialogOptionContext(
                    CommonStringId.TESTING_SOME_TEXT_FOR_TESTING,
                    CommonStringId.TESTING_TEST_BUTTON_TWO,
                    icon=CommonIconUtils.load_arrow_navigate_into_icon()),
                on_chosen=_on_option_chosen))

        option_dialog.add_option(
            CommonDialogObjectOption(
                'Option 3',
                'Value 3',
                CommonDialogOptionContext(
                    CommonLocalizationUtils.create_localized_string('Value 3'),
                    CommonStringId.TESTING_TEST_BUTTON_TWO,
                    icon=CommonIconUtils.load_arrow_navigate_into_icon()),
                on_chosen=_on_option_chosen))

        option_dialog.show(sim_info=CommonSimUtils.get_active_sim_info())
    except Exception as ex:
        CommonExceptionHandler.log_exception(ModInfo.get_identity(),
                                             'Failed to show dialog',
                                             exception=ex)
        output('Failed to show dialog, please locate your exception log file.')
    output('Done showing.')
class CommonInteraction(Interaction, HasClassLog):
    """CommonInteraction(...)

    An inheritable class that provides a way to create Custom Interactions.

    .. note::

       It is recommended to inherit from one of the following classes instead of :class:`CommonInteraction` directly:

       * :class:`CommonImmediateSuperInteraction`
       * :class:`CommonMixerInteraction`
       * :class:`CommonSocialMixerInteraction`
       * :class:`CommonSuperInteraction`
       * :class:`CommonTerrainInteraction`

    .. warning:: Due to an issue with how Read The Docs functions, the base classes of this class will have different namespaces than they do in the source code!
    """

    # noinspection PyMissingOrEmptyDocstring
    @classmethod
    def get_mod_identity(cls) -> CommonModIdentity:
        return ModInfo.get_identity()

    def __init__(self, *_: Any, **__: Any):
        super().__init__(*_, **__)
        HasClassLog.__init__(self)

    @classmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=TestResult.NONE)
    def _test(cls, target: Any, context: InteractionContext,
              **kwargs) -> TestResult:
        try:
            test_result = cls.on_test(context.sim, target, context, **kwargs)
        except Exception as ex:
            mod_identity = cls.get_mod_identity()
            CommonExceptionHandler.log_exception(
                mod_identity,
                'Error occurred while running interaction \'{}\' on_test.'.
                format(cls.__name__),
                exception=ex)
            return TestResult.NONE
        if test_result is None:
            return super()._test(target, context, **kwargs)
        if not isinstance(test_result, TestResult):
            raise RuntimeError(
                'Interaction on_test did not result in a TestResult, instead got {}. {}'
                .format(pformat(test_result), cls.__name__))
        if test_result.result is False:
            if test_result.tooltip is not None:
                tooltip = CommonLocalizationUtils.create_localized_tooltip(
                    test_result.tooltip)
            elif test_result.reason is not None:
                tooltip = CommonLocalizationUtils.create_localized_tooltip(
                    test_result.reason)
            else:
                tooltip = None
            return cls.create_test_result(test_result.result,
                                          test_result.reason,
                                          tooltip=tooltip)
        return super()._test(target, context, **kwargs)

    def _trigger_interaction_start_event(self: 'CommonInteraction'):
        try:
            super()._trigger_interaction_start_event()
            self.on_started(self.sim, self.target)
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' on_started.'.
                format(self.__class__.__name__),
                exception=ex)

    # noinspection PyMissingOrEmptyDocstring
    def apply_posture_state(
            self,
            posture_state: PostureState,
            participant_type: ParticipantType = ParticipantType.Actor,
            sim: Sim = DEFAULT):
        try:
            (new_posture_state, new_participant_type,
             new_sim) = self.modify_posture_state(
                 posture_state, participant_type=participant_type, sim=sim)
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' modify_posture_state.'
                .format(self.__class__.__name__),
                exception=ex)
            return None, None, None
        return super().apply_posture_state(
            new_posture_state,
            participant_type=new_participant_type,
            sim=new_sim)

    def kill(self) -> bool:
        """kill()

        Kill the interaction. (Hard Cancel)

        :return: True, if the interaction was killed successfully. False, if the interaction was not killed successfully.
        :rtype: bool
        """
        try:
            self.on_killed(self.sim, self.target)
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' on_killed.'.
                format(self.__class__.__name__),
                exception=ex)
        return super().kill()

    def cancel(self, finishing_type: FinishingType, cancel_reason_msg: str,
               **kwargs) -> bool:
        """cancel(finishing_type, cancel_reason_msg, **kwargs)

        Cancel the interaction. (Soft Cancel)

        :param finishing_type: The type of cancellation occurring.
        :type finishing_type: FinishingType
        :param cancel_reason_msg: The reason the interaction was cancelled.
        :type cancel_reason_msg: str
        :return: True, if the interaction was cancelled successfully. False, if the interaction was not cancelled successfully.
        :rtype: bool
        """
        try:
            self.on_cancelled(self.sim, self.target, finishing_type,
                              cancel_reason_msg, **kwargs)
            return super().cancel(finishing_type, cancel_reason_msg, **kwargs)
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' cancel.'.
                format(self.__class__.__name__),
                exception=ex)

    def on_reset(self: 'CommonInteraction'):
        """on_reset()

        A function that occurs upon an interaction being reset.

        """
        try:
            self._on_reset(self.sim, self.target)
            return super().on_reset()
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' on_reset.'.
                format(self.__class__.__name__),
                exception=ex)

    def _post_perform(self: 'CommonInteraction'):
        try:
            self.on_performed(self.sim, self.target)
            return super()._post_perform()
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' _post_perform.'
                .format(self.__class__.__name__),
                exception=ex)

    def send_current_progress(self, *args: Any, **kwargs: Any):
        """send_current_progress(*args, **kwargs)

        A function that occurs upon a progress bar update.

        """
        try:
            result = self._send_current_progress(self.sim, self.target, *args,
                                                 **kwargs)
            if result is not None:
                return result
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' send_current_progress.'
                .format(self.__class__.__name__),
                exception=ex)
        return super().send_current_progress(*args, **kwargs)

    def setup_asm_default(self, asm: NativeAsm, *args, **kwargs) -> bool:
        """setup_asm_default(asm, *args, **kwargs)

        A function that occurs when setting up the Animation State Machine.

        :param asm: An instance of the Animation State Machine
        :type asm: NativeAsm
        :return: True, if the ASM was setup properly. False, if not.
        :rtype: bool
        """
        try:
            result = self._setup_asm_default(self.sim, self.target, asm, *args,
                                             **kwargs)
            if result is not None:
                return result
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' setup_asm_default.'
                .format(self.__class__.__name__),
                exception=ex)
        return super().setup_asm_default(asm, *args, **kwargs)

    # The following functions are hooks into various parts of an interaction override them in your own interaction to provide custom functionality.

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=TestResult.NONE)
    def create_test_result(
            result: bool,
            reason: str = None,
            text_tokens: Union[Tuple[Any], List[Any], Set[Any]] = (),
            tooltip: Union[int, str,
                           CommonLocalizationUtils.LocalizedTooltip] = None,
            icon=None,
            influence_by_active_mood: bool = False) -> TestResult:
        """create_test_result(\
            result,\
            reason=None,\
            text_tokens=(),\
            tooltip=None,\
            icon=None,\
            influence_by_active_mood=False\
        )

        Create a TestResult with the specified information.

        .. note:: TestResult is an object used to disable, hide, or display tooltips on interactions. See :func:`~on_test` for more information.

        :param result: The result of a test. True for passed, False for failed.
        :type result: bool
        :param reason: The reason for the Test Result (This is displayed as a tooltip to the player when the interaction is disabled).
        :type reason: str, optional
        :param text_tokens: Any text tokens to include format into the reason.
        :type text_tokens: Union[Tuple[Any], List[Any], Set[Any]], optional
        :param tooltip: The tooltip displayed when hovering the interaction while it is disabled.
        :type tooltip: Union[int, str, LocalizedTooltip], optional
        :param icon: The icon of the outcome.
        :type icon: _resourceman.Key, optional
        :param influence_by_active_mood: If true, the Test Result will be influenced by the active mood.
        :type influence_by_active_mood: bool, optional
        :return: The desired outcome for a call of :func:`~on_test`, default is `TestResult.NONE`
        :rtype: TestResult
        """
        return TestResult(result,
                          reason,
                          *text_tokens,
                          tooltip=tooltip,
                          icon=icon,
                          influence_by_active_mood=influence_by_active_mood)

    @classmethod
    def on_test(cls, interaction_sim: Sim, interaction_target: Any,
                interaction_context: InteractionContext,
                **kwargs) -> TestResult:
        """on_test(interaction_sim, interaction_target, interaction_context, **kwargs)

        A hook that occurs upon the interaction being tested for availability.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :param interaction_context: The context of the interaction.
        :type interaction_context: InteractionContext
        :return: The outcome of testing the availability of the interaction
        :rtype: TestResult
        """
        return TestResult.TRUE

    def on_started(self, interaction_sim: Sim,
                   interaction_target: Any) -> bool:
        """on_started(interaction_sim, interaction_target)

        A hook that occurs upon the interaction being started.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :return: True, if the interaction hook was executed successfully. False, if the interaction hook was not executed successfully.
        :rtype: bool
        """
        pass

    # noinspection PyUnusedLocal
    def on_killed(self, interaction_sim: Sim, interaction_target: Any) -> bool:
        """on_killed(interaction_sim, interaction_target)

        A hook that occurs upon the interaction being killed.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :return: True, if the interaction hook was executed successfully. False, if the interaction hook was not executed successfully.
        :rtype: bool
        """
        return True

    def on_cancelled(self, interaction_sim: Sim, interaction_target: Any,
                     finishing_type: FinishingType, cancel_reason_msg: str,
                     **kwargs) -> None:
        """on_cancelled(interaction_sim, interaction_target, finishing_type, cancel_reason_msg, **kwargs)

        A hook that occurs upon the interaction being cancelled.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :param finishing_type: The type of cancellation of the interaction.
        :type finishing_type: FinishingType
        :param cancel_reason_msg: The reason the interaction was cancelled.
        :type cancel_reason_msg: str
        """
        pass

    def _on_reset(self, interaction_sim: Sim, interaction_target: Any) -> None:
        """_on_reset(interaction_sim, interaction_target)

        A hook that occurs upon the interaction being reset.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        """
        pass

    def on_performed(self, interaction_sim: Sim,
                     interaction_target: Any) -> None:
        """on_performed(interaction_sim, interaction_target)

        A hook that occurs after the interaction has been performed.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        """
        pass

    def modify_posture_state(
            self,
            posture_state: PostureState,
            participant_type: ParticipantType = ParticipantType.Actor,
            sim: Sim = DEFAULT) -> Tuple[PostureState, ParticipantType, Sim]:
        """modify_posture_state(posture_state, participant_type=ParticipantType.Actor, sim=DEFAULT)

        A hook that allows modification of the posture state of the interactions participants.

        :param posture_state: The posture state being modified.
        :type posture_state: PostureState
        :param participant_type: The position in the interaction that the `sim` is considered at. Example: `ParticipantType.Actor` represents the source Sim of the interaction.
        :type participant_type: ParticipantType, optional
        :param sim: The Sim the posture state is being applied to.
        :type sim: Sim, optional
        :return: Return a modified PostureState, ParticipantType, and Sim.
        :rtype: Tuple[PostureState, ParticipantType, Sim]
        """
        return posture_state, participant_type, sim

    # noinspection PyUnusedLocal
    def _setup_asm_default(self, interaction_sim: Sim, interaction_target: Any,
                           interaction_asm: NativeAsm, *args,
                           **kwargs) -> Union[bool, None]:
        """_setup_asm_default(interaction_sim, interaction_target, asm, *args, **kwargs)

        A hook that occurs upon the animation state machine being setup for the interaction.

        .. warning:: The returned value from here replaces the original returned value. Return None from here to return the original value.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :param interaction_asm: An instance of an Animation State Machine
        :type interaction_asm: NativeAsm
        :return: True, if the ASM was setup properly. False, if not. or None to run through the original code.
        :rtype: bool
        """
        return None

    # noinspection PyUnusedLocal
    def _send_current_progress(self, interaction_sim: Sim,
                               interaction_target: Any, *args,
                               **kwargs) -> Union[bool, None]:
        """_send_current_progress(interaction_sim, interaction_target, *args, **kwargs)

        A hook that occurs upon sending the current progress for the interaction.

        .. warning:: The returned value from here replaces the original returned value.

        :param interaction_sim: The source Sim of the interaction.
        :type interaction_sim: Sim
        :param interaction_target: The target Object of the interaction.
        :type interaction_target: Any
        :return: True, if progress was sent successfully. False, if not. Return None to run the original code.
        :rtype: bool
        """
        return None

    def set_current_progress_bar(self,
                                 percent: float,
                                 rate_change: float,
                                 start_message: bool = True):
        """set_current_progress_bar(initial_value, progress_rate)

        Set the current progress rate of the interaction.

        :param percent: A percentage indicating the starting progress.
        :type percent: float
        :param rate_change: A value that indicates how fast progress will be made.
        :type rate_change: float
        :param start_message: If True, progress will begin changing immediately. If False, it will not. Default is True.
        :type start_message: bool, optional
        """
        try:
            self._send_progress_bar_update_msg(percent,
                                               rate_change,
                                               start_msg=start_message)
        except Exception as ex:
            CommonExceptionHandler.log_exception(
                self.mod_identity,
                'Error occurred while running interaction \'{}\' set_current_progress_bar.'
                .format(self.__class__.__name__),
                exception=ex)
Пример #17
0
class CommonStatisticUtils:
    """Utilities for manipulating Statistics.

    """
    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=-1.0)
    def get_statistic_initial_value(statistic_id: int) -> float:
        """get_statistic_initial_value(statistic_id)

        Retrieve the Initial Value of a Statistic.

        :param statistic_id: The identifier of the Statistic to use.
        :type statistic_id: int
        :return: The initial value of the statistic.
        :rtype: float
        """
        statistic_instance = CommonStatisticUtils._load_statistic_instance(
            statistic_id)
        if statistic_instance is None:
            return -1.0
        if not hasattr(statistic_instance, 'get_initial_value'):
            return statistic_instance.default_value
        return statistic_instance.get_initial_value()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=-1.0)
    def get_statistic_min_value(statistic_id: int) -> float:
        """get_statistic_min_value(statistic_id)

        Retrieve the Minimum Value of a Statistic.

        :param statistic_id: The identifier of the Statistic to use.
        :type statistic_id: int
        :return: The minimum value of the statistic.
        :rtype: float
        """
        statistic_instance = CommonStatisticUtils._load_statistic_instance(
            statistic_id)
        if statistic_instance is None:
            return -1.0
        return statistic_instance.min_value

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=-1.0)
    def get_statistic_max_value(statistic_id: int) -> float:
        """get_statistic_max_value(statistic_id)

        Retrieve the Maximum Value of a Statistic.

        :param statistic_id: The identifier of the Statistic to use.
        :type statistic_id: int
        :return: The maximum value of the statistic.
        :rtype: float
        """
        statistic_instance = CommonStatisticUtils._load_statistic_instance(
            statistic_id)
        if statistic_instance is None:
            return -1.0
        return statistic_instance.max_value

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def _load_statistic_instance(statistic_id: int) -> Union[Statistic, None]:
        statistic_instance = CommonResourceUtils.load_instance(
            Types.STATISTIC, statistic_id)
        if statistic_instance is None:
            return None
        return statistic_instance
class CommonSimPregnancyUtils:
    """Utilities for manipulating the pregnancy status of Sims.

    """
    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def is_pregnant(sim_info: SimInfo) -> bool:
        """is_pregnant(sim_info)

        Determine if the specified Sim is pregnant.

        :param sim_info: The Sim to check.
        :type sim_info: SimInfo
        :return: True, if the Sim is pregnant. False, if not.
        :rtype: bool
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        return pregnancy_tracker.is_pregnant

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def start_pregnancy(
            sim_info: SimInfo,
            partner_sim_info: SimInfo,
            pregnancy_origin: PregnancyOrigin = PregnancyOrigin.DEFAULT
    ) -> bool:
        """start_pregnancy(sim_info, partner_sim_info, pregnancy_origin=PregnancyOrigin.DEFAULT)

        Start a pregnancy between a Sim and a Partner Sim.

        :param sim_info: The Sim getting pregnant.
        :type sim_info: SimInfo
        :param partner_sim_info: The Sim that is getting the other Sim pregnant.
        :type partner_sim_info: SimInfo
        :param pregnancy_origin: The origin of the pregnancy. Default is PregnancyOrigin.DEFAULT.
        :type pregnancy_origin: PregnancyOrigin, optional
        :return: True, if the Sim is successfully impregnated by the Partner Sim. False, if not.
        :rtype: bool
        """
        if not CommonHouseholdUtils.has_free_household_slots(sim_info):
            return False
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        pregnancy_tracker.start_pregnancy(sim_info,
                                          partner_sim_info,
                                          pregnancy_origin=pregnancy_origin)
        pregnancy_tracker.clear_pregnancy_visuals()
        CommonSimStatisticUtils.set_statistic_value(
            sim_info, CommonStatisticId.PREGNANCY, 1.0)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def clear_pregnancy(sim_info: SimInfo) -> bool:
        """clear_pregnancy(sim_info)

        Clear the pregnancy status of a Sim.

        :param sim_info: The Sim being cleared.
        :type sim_info: SimInfo
        :return: True, if successful. False, if not.
        :rtype: bool
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return False
        sim_info.pregnancy_tracker.clear_pregnancy()
        CommonSimStatisticUtils.remove_statistic(sim_info,
                                                 CommonStatisticId.PREGNANCY)
        return True

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def can_be_impregnated(sim_info: SimInfo) -> bool:
        """can_be_impregnated(sim_info)

        Determine if a Sim can be impregnated.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: True, if they can. False, if they cannot.
        :rtype: bool
        """
        from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils
        from sims4communitylib.enums.traits_enum import CommonTraitId
        if CommonSpeciesUtils.is_human(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info, CommonTraitId.
                    GENDER_OPTIONS_PREGNANCY_CAN_NOT_BE_IMPREGNATED):
                return False
            return CommonTraitUtils.has_trait(
                sim_info,
                CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_BE_IMPREGNATED)
        elif CommonSpeciesUtils.is_pet(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)
        return False

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=False)
    def can_impregnate(sim_info: SimInfo) -> bool:
        """can_impregnate(sim_info)

        Determine if a Sim can impregnate other sims.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: True, if they can. False, if they cannot.
        :rtype: bool
        """
        from sims4communitylib.utils.sims.common_trait_utils import CommonTraitUtils
        from sims4communitylib.enums.traits_enum import CommonTraitId
        if CommonSpeciesUtils.is_human(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_NOT_IMPREGNATE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info,
                CommonTraitId.GENDER_OPTIONS_PREGNANCY_CAN_IMPREGNATE)
        elif CommonSpeciesUtils.is_pet(sim_info):
            if CommonTraitUtils.has_trait(
                    sim_info,
                    CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_NOT_REPRODUCE):
                return False
            return CommonTraitUtils.has_trait(
                sim_info, CommonTraitId.PREGNANCY_OPTIONS_PET_CAN_REPRODUCE)
        return False

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def get_partner_of_pregnant_sim(sim_info: SimInfo) -> Union[SimInfo, None]:
        """get_partner_of_pregnant_sim(sim_info)

        Retrieve a SimInfo object of the Sim that impregnated the specified Sim.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The Sim that has impregnated the specified Sim or None if the Sim does not have a partner.
        :rtype: Union[SimInfo, None]
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return None
        return pregnancy_tracker.get_partner()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=0.0)
    def get_pregnancy_progress(sim_info: SimInfo) -> float:
        """get_pregnancy_progress(sim_info)

        Retrieve the pregnancy progress of a Sim.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The current progress of the pregnancy of a Sim.
        :rtype: float
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None or not CommonSimPregnancyUtils.is_pregnant(
                sim_info):
            return 0.0
        pregnancy_commodity_type = pregnancy_tracker.PREGNANCY_COMMODITY_MAP.get(
            CommonSpeciesUtils.get_species(sim_info))
        statistic_tracker = sim_info.get_tracker(pregnancy_commodity_type)
        pregnancy_commodity = statistic_tracker.get_statistic(
            pregnancy_commodity_type, add=False)
        if not pregnancy_commodity:
            return 0.0
        return pregnancy_commodity.get_value()

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=0.0)
    def get_pregnancy_rate(sim_info: SimInfo) -> float:
        """get_pregnancy_rate(sim_info)

        Retrieve the rate at which pregnancy progresses.

        :param sim_info: The Sim being checked.
        :type sim_info: SimInfo
        :return: The rate at which the pregnancy state of a Sim is progressing.
        :rtype: float
        """
        pregnancy_tracker = CommonSimPregnancyUtils._get_pregnancy_tracker(
            sim_info)
        if pregnancy_tracker is None:
            return 0.0
        return pregnancy_tracker.PREGNANCY_RATE

    @staticmethod
    def get_in_labor_buff(sim_info: SimInfo) -> Union[int, CommonBuffId]:
        """get_in_labor_buff(sim_info)

        Retrieve an In Labor buff appropriate for causing the Sim to go into labor (Give Birth).

        :param sim_info: An instance of a Sim.
        :type sim_info: SimInfo
        :return: The decimal identifier of a Buff that will cause the specified Sim to go into labor. If no appropriate Buff is found, -1 will be returned.
        :rtype: Union[int, CommonBuffId]
        """
        from sims4communitylib.utils.sims.common_gender_utils import CommonGenderUtils
        sim_name = CommonSimNameUtils.get_full_name(sim_info)
        log.debug(
            'Locating appropriate Buff for inducing labor in \'{}\'.'.format(
                sim_name))
        is_female = CommonGenderUtils.is_female(sim_info)
        if CommonSpeciesUtils.is_human(sim_info):
            log.debug('\'{}\' is Human.'.format(sim_name))
            if is_female:
                log.debug('\'{}\' is Female.'.format(sim_name))
                return CommonBuffId.PREGNANCY_IN_LABOR
            else:
                log.debug('\'{}\' is Male.'.format(sim_name))
                return CommonBuffId.PREGNANCY_IN_LABOR_MALE
        elif CommonSpeciesUtils.is_dog(sim_info):
            log.debug('\'{}\' is a Dog.'.format(sim_name))
            if is_female:
                log.debug('\'{}\' is Female.'.format(sim_name))
                return CommonBuffId.PREGNANCY_IN_LABOR_PET_DOG
        elif CommonSpeciesUtils.is_cat(sim_info):
            log.debug('\'{}\' is a Cat.'.format(sim_name))
            if is_female:
                log.debug('\'{}\' is Female.'.format(sim_name))
                return CommonBuffId.PREGNANCY_IN_LABOR_PET_CAT
        log.debug(
            'No appropriate Buff located to induce labor in \'{}\'.'.format(
                sim_name))
        return -1

    @staticmethod
    @CommonExceptionHandler.catch_exceptions(ModInfo.get_identity(),
                                             fallback_return=None)
    def _get_pregnancy_tracker(
            sim_info: SimInfo) -> Union[PregnancyTracker, None]:
        if sim_info is None:
            return None
        return sim_info.pregnancy_tracker
    def run_with_sims(self,
                      sim_info: SimInfo,
                      chosen_sim_info: SimInfo,
                      on_completed: Callable[[bool],
                                             None] = CommonFunctionUtils.noop):
        def _on_none_chosen(_: Any, __: Any):
            try:
                CommonSimGenealogyUtils.remove_family_relations_with(
                    sim_info, chosen_sim_info)
                CommonSimGenealogyUtils.remove_family_relations_with(
                    chosen_sim_info, sim_info)
            except Exception as ex:
                self.log.error('Failed to remove family relations',
                               exception=ex)
            self.run_with_sims(sim_info,
                               chosen_sim_info,
                               on_completed=on_completed)

        def _on_bit_chosen(
                _: Any,
                chosen_operation: S4CMSetSimAAsRelationToSimBOperation):
            if _ is None or chosen_operation is None:
                return
            if chosen_operation.has_relation(sim_info, chosen_sim_info):
                self.run_with_sims(sim_info,
                                   chosen_sim_info,
                                   on_completed=on_completed)
                return

            def _on_yes_selected(_: Any):
                if chosen_operation is None:
                    self.run_with_sims(sim_info,
                                       chosen_sim_info,
                                       on_completed=on_completed)
                    return

                def _on_completed(___: bool):
                    self.run_with_sims(sim_info,
                                       chosen_sim_info,
                                       on_completed=on_completed)

                chosen_operation.run(sim_info,
                                     chosen_sim_info,
                                     on_completed=_on_completed)

            def _on_no_selected(_: Any):
                self.run_with_sims(sim_info,
                                   chosen_sim_info,
                                   on_completed=on_completed)

            confirmation = CommonOkCancelDialog(
                S4CMStringId.CONFIRMATION,
                S4CMSimControlMenuStringId.
                SIM_WILL_BECOME_RELATIONSHIP_TO_SIM_CONFIRMATION_TEXT,
                description_tokens=(sim_info,
                                    chosen_operation.get_display_name(
                                        chosen_sim_info,
                                        sim_info), chosen_sim_info),
                ok_text_identifier=S4CMStringId.YES,
                cancel_text_identifier=S4CMStringId.NO)
            confirmation.show(on_ok_selected=_on_yes_selected,
                              on_cancel_selected=_on_no_selected)
            return True

        option_dialog = CommonChooseButtonOptionDialog(
            ModInfo.get_identity(),
            S4CMSimControlMenuStringId.CHOOSE_FAMILY_RELATION,
            S4CMSimControlMenuStringId.CHOOSE_WHAT_SIM_WILL_BECOME_TO_SIM,
            description_tokens=(sim_info, chosen_sim_info),
            include_previous_button=True,
            on_previous=lambda: on_completed(False),
            on_close=lambda: on_completed(False))

        options = list()
        has_a_relation = False
        for relationship_operation in self._relation_operations:
            relationship_operation: S4CMSetSimAAsRelationToSimBOperation = relationship_operation
            display_name = relationship_operation.get_display_name(
                chosen_sim_info, sim_info)
            has_relation = relationship_operation.has_relation(
                sim_info, chosen_sim_info)
            if has_relation:
                has_a_relation = True
            options.append(
                CommonDialogButtonOption(
                    str(relationship_operation.relationship_bit_id),
                    relationship_operation,
                    CommonDialogResponseOptionContext(
                        CommonLocalizationUtils.colorize(
                            display_name, CommonLocalizedStringColor.GREEN)
                        if has_relation else display_name,
                        disabled_text_identifier=relationship_operation.
                        get_disabled_text(sim_info, chosen_sim_info)),
                    on_chosen=_on_bit_chosen))

        option_dialog.add_option(
            CommonDialogButtonOption(
                'None',
                None,
                CommonDialogResponseOptionContext(
                    CommonLocalizationUtils.colorize(
                        S4CMStringId.NONE, CommonLocalizedStringColor.GREEN)
                    if not has_a_relation else S4CMStringId.NONE, ),
                on_chosen=_on_none_chosen))

        for option in options:
            option_dialog.add_option(option)

        if not option_dialog.has_options():
            on_completed(False)
            return

        option_dialog.show(sim_info=sim_info)
"""
The Sims 4 Community Library is licensed under the Creative Commons Attribution 4.0 International public license (CC BY 4.0).
https://creativecommons.org/licenses/by/4.0/
https://creativecommons.org/licenses/by/4.0/legalcode

Copyright (c) COLONOLNUTTY
"""
# The purpose of this file is to fix the fact that when trying to access the "full_name" attribute on Sims an empty string is returned.
# noinspection PyBroadException
from sims.sim_info import SimInfo
from sims4communitylib.modinfo import ModInfo
from sims4communitylib.utils.common_injection_utils import CommonInjectionUtils
from sims4communitylib.utils.sims.common_sim_name_utils import CommonSimNameUtils
from sims4communitylib.utils.sims.common_sim_utils import CommonSimUtils


@CommonInjectionUtils.inject_safely_into(ModInfo.get_identity(), SimInfo,
                                         'full_name')
def _common_fix_full_name_returning_empty_string(original, self: SimInfo, *_,
                                                 **__):
    original_value = original(self, *_, **__)
    if original_value == '':
        return CommonSimNameUtils.get_full_name(
            CommonSimUtils.get_sim_info(self))
    return original_value