def mod_identity(self) -> CommonModIdentity: return self._mod_identity or ModInfo.get_identity()
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)
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
""" 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)
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)
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()
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)
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